2008-10-08 08:59:54

by Zhao Forrest

[permalink] [raw]
Subject: PBAP storage plugin API proposal

Hi experts,

I'm implementing PBAP server based on obexd. In order to support
various PBAP backend storage each type of PBAP backend storage should
be implemented as a plugin of PBAP server. So we propose the initial
PBAP storage plugin API as follows. Basically the bellows are defined
in pbap_storage_plugin.h
====================================================================
typedef void* pullphonebook_t;
typedef void* pullvcardlisting_t;
typedef void* pullvcardentry_t;

struct pbap_storage_operations {
pullphonebook_t* (*pullphonebook_init) (const gchar *object_name,
guint64 filter, guint8 format,
guint16 max_list_count, guint16 list_start_offset,
guint16 *phonebook_size, guint8 *new_missed_calls);
gint32 (*pullphonebook) (pullphonebook_t *handle, guint8 *buf,
guint16 buf_len);
void (*pullphonebook_free) (pullphonebook_t *handle);

pullvcardlisting_t* (*pullvcardlisting_init) (const gchar *object_name,
guint8 order, guint8 search_attr, gchar
*search_val,
guint16 max_list_count, guint16 list_start_offset,
guint16 *phonebook_size, guint8 *new_missed_calls);
gint32 (*pullvcardlisting) (pullvcardlisting_t *handle, guint8 *buf,
guint16 buf_len);
void (*pullvcardlisting_free) (pullvcardlisting_t *handle);

pullvcardentry_t* (*pullvcardentry_init) (const gchar *object_name,
guint64 filter, guint8 format);
gint32 (*pullvcardentry) (pullvcardentry_t *handle, guint8 *buf,
guint16 buf_len);
void (*pullvcardentry_free) (pullvcardentry_t *handle);
};

guint8 pbap_storage_operations_register(struct pbap_storage_operations *ops);

struct obex_pbap_storage_plugin_desc {
const char *name;
int (*init) (void);
void (*exit) (void);
};

#define OBEX_PBAP_STORAGE_PLUGIN_DEFINE(name,init,exit) \
struct obex_pbap_storage_plugin_desc
obex_pbap_storage_plugin_desc = { \
name, init, exit \
};
====================================================================
The plugin framework is similar to the one used in bluez and obexd. A
particular PBAP storage plugin program should define its own "struct
pbap_storage_operations" and call pbap_storage_operations_register()
in obex_pbap_storage_plugin_desc.init() to register these callback
functions to PBAP server.

Here we use "pullphonebook" as an example to explain the PBAP storage
plugin API usage.
For example when OBEX PBAP server receives a "PullPhoneBook" request
from PBAP client, it first calls
pbap_storage_ops->pullphonebook_init() to get a handle, phonebook_size
and new_missed_calls as returned value; then it calls
pbap_storage_ops-> pullphonebook() to get the phonebook object until
the return value is 0; lastly it calls pbap_storage_ops->
pullphonebook_free() to release the handle.

The PBAP spec is at
http://www.bluetooth.com/NR/rdonlyres/58FC38BF-9ED6-49FF-81CF-E0B95B130D72/7761/PBAP_SPEC_V10r00.pdf.

Your comments are welcome!

Thanks,
Forrest


2008-10-20 16:12:39

by Marcel Holtmann

[permalink] [raw]
Subject: Re: PBAP storage plugin API proposal

Hi Forrest,

> >> Yes. My proposed PBAP storage API follows this rule, but lacks the
> >> method to unregister the operations. Will add it later.
> >
> > I put some prototype declarations into the obexd repository. The
> > important part is that we have to do this in an async way. We can't
> > block while retrieving the phonebook information.
> >
>
> I'm implementing PBAP driver framework and a simple(or prototype) PBAP
> driver based on your prototype declarations. Will add some extentions
> to the prototype declarations if necessary.
> To do that in an async way I think the basic idea is:
> 1 when PBAP driver is loaded(or initialized), fork() is invoked to run
> PBAP driver in child process

NO WAY. No fork() and no threads. That is just not needed. You get the
callback and then you just use phonebook_return(). Check the code that
is actually in the repository. It needs a little bit more work to get
the details right, but it works how it should be.

Also we do have a phonebook_context that presents a lifetime of a
transaction. It needs to be extended and used properly, but it is how
this is done.

Also the pull phonebook, pull vcard listing and pull vcard entry with
one specific context can not run simultaneously. The will run after each
if at all. So we init a context and then we destroy the context once we
are done with it. In between we can use the any callback.

> 2 the Unix domain socket is used to communicate between PBAP server
> and PBAP driver; and PBAP server acts as client role at the one end of
> socket, PBAP driver acts as server role at the other end of socket

NO WAY. Come on. Don't try to make this more complicated. Think simple
and I already put all the ground works into the repository. We just need
to parse the OBEX request properly and return the result from the
plugin.

And remember that obexd is designed for embedded systems and every
process that we have to run additionally costs us. Not to mention that
we end up with crazy dependencies for boot.

> 3 everytime a PBAP client connects to PBAP server(i.e. a OBEX session
> is initiated), PBAP server initiates a session(or a socket) with PBAP
> driver by invoking connect(). Then PBAP server sends subsequent PBAP
> request(pullphonebook, pullvcardlisting, pullvcardentry) through this
> socket; PBAP driver sends back the requested data through the socket
> asyncronously.
> Am I right? I'd like to first make the basic design ideas clear in
> order to avoid the unnecessary misunderstanding or confusion before
> starting to write the code.

The basic design is already pushed into the repository. Including sample
code for accessing the Evolution Data Server via the ebook plugin.

Start looking at that code, because that is the way to go. No need for
an over-complicated design. The whole code is only missing some minor
pieces I didn't have time for over the weekend.

Regards

Marcel



2008-10-20 09:21:05

by Zhao Forrest

[permalink] [raw]
Subject: Re: PBAP storage plugin API proposal

>> Yes. My proposed PBAP storage API follows this rule, but lacks the
>> method to unregister the operations. Will add it later.
>
> I put some prototype declarations into the obexd repository. The
> important part is that we have to do this in an async way. We can't
> block while retrieving the phonebook information.
>

I'm implementing PBAP driver framework and a simple(or prototype) PBAP
driver based on your prototype declarations. Will add some extentions
to the prototype declarations if necessary.
To do that in an async way I think the basic idea is:
1 when PBAP driver is loaded(or initialized), fork() is invoked to run
PBAP driver in child process
2 the Unix domain socket is used to communicate between PBAP server
and PBAP driver; and PBAP server acts as client role at the one end of
socket, PBAP driver acts as server role at the other end of socket
3 everytime a PBAP client connects to PBAP server(i.e. a OBEX session
is initiated), PBAP server initiates a session(or a socket) with PBAP
driver by invoking connect(). Then PBAP server sends subsequent PBAP
request(pullphonebook, pullvcardlisting, pullvcardentry) through this
socket; PBAP driver sends back the requested data through the socket
asyncronously.
Am I right? I'd like to first make the basic design ideas clear in
order to avoid the unnecessary misunderstanding or confusion before
starting to write the code.

Thanks,
Forrest

2008-10-18 04:29:42

by Marcel Holtmann

[permalink] [raw]
Subject: Re: PBAP storage plugin API proposal

Hi Forrest,

> > use the generic per plugin defines and its init and exit functions and
> > then provide methods to register and unregister the operations.
> >
> Yes. My proposed PBAP storage API follows this rule, but lacks the
> method to unregister the operations. Will add it later.

I put some prototype declarations into the obexd repository. The
important part is that we have to do this in an async way. We can't
block while retrieving the phonebook information.

> > Please keep in mind that in theory we can load more than one of these
> > phonebook "drivers".
> >
> Do you mean obexd could load multiple PBAP server plugin instances
> at the same time?

Only one instance of the plugin, but multiple different ones.

> Or one PBAP server instance could load multiple PBAP storage plugins
> at the same time?

Yes. That could be possible.

Regards

Marcel



2008-10-09 01:43:30

by Zhao Forrest

[permalink] [raw]
Subject: Re: PBAP storage plugin API proposal

>
> use the generic per plugin defines and its init and exit functions and
> then provide methods to register and unregister the operations.
>
Yes. My proposed PBAP storage API follows this rule, but lacks the
method to unregister the operations. Will add it later.

> Please keep in mind that in theory we can load more than one of these
> phonebook "drivers".
>
Do you mean obexd could load multiple PBAP server plugin instances
at the same time?
Or one PBAP server instance could load multiple PBAP storage plugins
at the same time?

Thanks,
Forrest

2008-10-08 09:17:36

by Marcel Holtmann

[permalink] [raw]
Subject: Re: PBAP storage plugin API proposal

Hi Forrest,

> I'm implementing PBAP server based on obexd. In order to support
> various PBAP backend storage each type of PBAP backend storage should
> be implemented as a plugin of PBAP server. So we propose the initial
> PBAP storage plugin API as follows. Basically the bellows are defined
> in pbap_storage_plugin.h
> ====================================================================
> typedef void* pullphonebook_t;
> typedef void* pullvcardlisting_t;
> typedef void* pullvcardentry_t;
>
> struct pbap_storage_operations {
> pullphonebook_t* (*pullphonebook_init) (const gchar *object_name,
> guint64 filter, guint8 format,
> guint16 max_list_count, guint16 list_start_offset,
> guint16 *phonebook_size, guint8 *new_missed_calls);
> gint32 (*pullphonebook) (pullphonebook_t *handle, guint8 *buf,
> guint16 buf_len);
> void (*pullphonebook_free) (pullphonebook_t *handle);
>
> pullvcardlisting_t* (*pullvcardlisting_init) (const gchar *object_name,
> guint8 order, guint8 search_attr, gchar
> *search_val,
> guint16 max_list_count, guint16 list_start_offset,
> guint16 *phonebook_size, guint8 *new_missed_calls);
> gint32 (*pullvcardlisting) (pullvcardlisting_t *handle, guint8 *buf,
> guint16 buf_len);
> void (*pullvcardlisting_free) (pullvcardlisting_t *handle);
>
> pullvcardentry_t* (*pullvcardentry_init) (const gchar *object_name,
> guint64 filter, guint8 format);
> gint32 (*pullvcardentry) (pullvcardentry_t *handle, guint8 *buf,
> guint16 buf_len);
> void (*pullvcardentry_free) (pullvcardentry_t *handle);
> };
>
> guint8 pbap_storage_operations_register(struct pbap_storage_operations *ops);
>
> struct obex_pbap_storage_plugin_desc {
> const char *name;
> int (*init) (void);
> void (*exit) (void);
> };
>
> #define OBEX_PBAP_STORAGE_PLUGIN_DEFINE(name,init,exit) \
> struct obex_pbap_storage_plugin_desc
> obex_pbap_storage_plugin_desc = { \
> name, init, exit \
> };
> ====================================================================
> The plugin framework is similar to the one used in bluez and obexd. A
> particular PBAP storage plugin program should define its own "struct
> pbap_storage_operations" and call pbap_storage_operations_register()
> in obex_pbap_storage_plugin_desc.init() to register these callback
> functions to PBAP server.

use the generic per plugin defines and its init and exit functions and
then provide methods to register and unregister the operations.

Please keep in mind that in theory we can load more than one of these
phonebook "drivers".

All (and I mean all) plugins in bluetoothd and obexd are treated the
same. It is up to their init and exit routines to do the job. This
allows us to have a generic plugin framework and not do invent it over
and over again.

Did anyone converted the picture from the whiteboard at the meeting into
some written details.

Regards

Marcel