mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-12-02 16:44:18 +08:00
obexd: Add first attempt at PBAP server implementation
This commit is contained in:
parent
b7b2ad11c6
commit
bac315ca0f
@ -133,6 +133,47 @@ const static gchar *ftp_record = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
|
||||
</attribute> \
|
||||
</record>";
|
||||
|
||||
const static gchar *pbap_record = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
|
||||
<record> \
|
||||
<attribute id=\"0x0001\"> \
|
||||
<sequence> \
|
||||
<uuid value=\"0x112f\"/> \
|
||||
</sequence> \
|
||||
</attribute> \
|
||||
\
|
||||
<attribute id=\"0x0004\"> \
|
||||
<sequence> \
|
||||
<sequence> \
|
||||
<uuid value=\"0x0100\"/> \
|
||||
</sequence> \
|
||||
<sequence> \
|
||||
<uuid value=\"0x0003\"/> \
|
||||
<uint8 value=\"%u\" name=\"channel\"/> \
|
||||
</sequence> \
|
||||
<sequence> \
|
||||
<uuid value=\"0x0008\"/> \
|
||||
</sequence> \
|
||||
</sequence> \
|
||||
</attribute> \
|
||||
\
|
||||
<attribute id=\"0x0009\"> \
|
||||
<sequence> \
|
||||
<sequence> \
|
||||
<uuid value=\"0x1130\"/> \
|
||||
<uint16 value=\"0x0100\" name=\"version\"/> \
|
||||
</sequence> \
|
||||
</sequence> \
|
||||
</attribute> \
|
||||
\
|
||||
<attribute id=\"0x0100\"> \
|
||||
<text value=\"%s\" name=\"name\"/> \
|
||||
</attribute> \
|
||||
\
|
||||
<attribute id=\"0x0314\"> \
|
||||
<uint8 value=\"0x01\"/> \
|
||||
</attribute> \
|
||||
</record>";
|
||||
|
||||
static uint32_t register_record(const gchar *name,
|
||||
guint16 service, guint8 channel)
|
||||
{
|
||||
@ -140,12 +181,15 @@ static uint32_t register_record(const gchar *name,
|
||||
gint handle;
|
||||
|
||||
switch (service) {
|
||||
case OBEX_OPUSH:
|
||||
case OBEX_OPP:
|
||||
record = g_markup_printf_escaped(opp_record, channel, name);
|
||||
break;
|
||||
case OBEX_FTP:
|
||||
record = g_markup_printf_escaped(ftp_record, channel, name);
|
||||
break;
|
||||
case OBEX_PBAP:
|
||||
record = g_markup_printf_escaped(pbap_record, channel, name);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -182,7 +226,7 @@ static gboolean connect_event(GIOChannel *io, GIOCondition cond, gpointer user_d
|
||||
info("New connection from: %s, channel %u, fd %d", address,
|
||||
raddr.rc_channel, nsk);
|
||||
|
||||
if (server->service == OBEX_OPUSH) {
|
||||
if (server->service == OBEX_OPP) {
|
||||
if (obex_session_start(nsk, server) < 0)
|
||||
close(nsk);
|
||||
|
||||
@ -292,11 +336,11 @@ failed:
|
||||
}
|
||||
|
||||
gint bluetooth_init(guint service, const gchar *name, const gchar *folder,
|
||||
guint8 channel, gboolean secure, gboolean auto_accept,
|
||||
const gchar *capability)
|
||||
guint8 channel, gboolean secure,
|
||||
gboolean auto_accept, const gchar *capability)
|
||||
{
|
||||
return server_register(service, name, channel,
|
||||
folder, secure, auto_accept, capability);
|
||||
return server_register(service, name, channel, folder,
|
||||
secure, auto_accept, capability);
|
||||
}
|
||||
|
||||
void bluetooth_exit(void)
|
||||
|
@ -46,12 +46,12 @@
|
||||
|
||||
#include "logging.h"
|
||||
#include "bluetooth.h"
|
||||
#include "phonebook.h"
|
||||
#include "obexd.h"
|
||||
#include "obex.h"
|
||||
|
||||
#define OPUSH_CHANNEL 9
|
||||
#define OPP_CHANNEL 9
|
||||
#define FTP_CHANNEL 10
|
||||
#define PBAP_CHANNEL 15
|
||||
|
||||
#define DEFAULT_ROOT_PATH "/tmp"
|
||||
|
||||
@ -59,26 +59,8 @@
|
||||
|
||||
static GMainLoop *main_loop = NULL;
|
||||
|
||||
static void test_phonebook(void)
|
||||
{
|
||||
struct phonebook_context *context;
|
||||
struct phonebook_driver *driver;
|
||||
|
||||
driver = phonebook_get_driver(NULL);
|
||||
if (driver == NULL)
|
||||
return;
|
||||
|
||||
context = phonebook_create(driver);
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
phonebook_pullphonebook(context);
|
||||
|
||||
phonebook_unref(context);
|
||||
}
|
||||
|
||||
static void tty_init(int service, const gchar *root_path, const gchar *capability,
|
||||
const gchar *devnode)
|
||||
static void tty_init(int service, const gchar *root_path,
|
||||
const gchar *capability, const gchar *devnode)
|
||||
{
|
||||
struct server *server;
|
||||
struct termios options;
|
||||
@ -113,26 +95,29 @@ static void tty_init(int service, const gchar *root_path, const gchar *capabilit
|
||||
}
|
||||
|
||||
static int server_start(int service, const char *root_path,
|
||||
gboolean auto_accept, const gchar *capability,
|
||||
const char *devnode)
|
||||
gboolean auto_accept, const gchar *capability,
|
||||
const char *devnode)
|
||||
{
|
||||
switch (service) {
|
||||
case OBEX_OPUSH:
|
||||
bluetooth_init(OBEX_OPUSH, "OBEX OPUSH server",
|
||||
root_path, OPUSH_CHANNEL, FALSE,
|
||||
auto_accept, capability);
|
||||
case OBEX_OPP:
|
||||
bluetooth_init(OBEX_OPP, "Object Push server",
|
||||
root_path, OPP_CHANNEL, FALSE,
|
||||
auto_accept, capability);
|
||||
if (devnode)
|
||||
tty_init(OBEX_OPUSH, root_path, capability,
|
||||
devnode);
|
||||
tty_init(OBEX_OPP, root_path, capability, devnode);
|
||||
break;
|
||||
case OBEX_FTP:
|
||||
bluetooth_init(OBEX_FTP, "OBEX FTP server",
|
||||
root_path, FTP_CHANNEL, TRUE,
|
||||
auto_accept, capability);
|
||||
|
||||
bluetooth_init(OBEX_FTP, "File Transfer server",
|
||||
root_path, FTP_CHANNEL, TRUE,
|
||||
auto_accept, capability);
|
||||
if (devnode)
|
||||
tty_init(OBEX_FTP, root_path, capability, devnode);
|
||||
break;
|
||||
case OBEX_PBAP:
|
||||
bluetooth_init(OBEX_PBAP, "Phonebook Access server",
|
||||
root_path, PBAP_CHANNEL, TRUE,
|
||||
auto_accept, capability);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -257,7 +242,7 @@ int main(int argc, char *argv[])
|
||||
option_capability = g_strdup(DEFAULT_CAP_FILE);
|
||||
|
||||
if (option_opp == TRUE)
|
||||
server_start(OBEX_OPUSH, option_root, option_autoaccept,
|
||||
server_start(OBEX_OPP, option_root, option_autoaccept,
|
||||
NULL, option_devnode);
|
||||
|
||||
if (option_ftp == TRUE)
|
||||
@ -265,7 +250,7 @@ int main(int argc, char *argv[])
|
||||
option_capability, option_devnode);
|
||||
|
||||
if (option_pbap == TRUE)
|
||||
test_phonebook();
|
||||
server_start(OBEX_PBAP, NULL, FALSE, NULL, NULL);
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = sig_term;
|
||||
|
@ -52,33 +52,40 @@
|
||||
#define RX_MTU 32767
|
||||
#define TX_MTU 32767
|
||||
|
||||
#define TARGET_SIZE 16
|
||||
static const guint8 FTP_TARGET[TARGET_SIZE] = { 0xF9, 0xEC, 0x7B, 0xC4,
|
||||
0x95, 0x3C, 0x11, 0xD2,
|
||||
0x98, 0x4E, 0x52, 0x54,
|
||||
0x00, 0xDC, 0x9E, 0x09 };
|
||||
#define TARGET_SIZE 16
|
||||
|
||||
static const guint8 FTP_TARGET[TARGET_SIZE] = {
|
||||
0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2,
|
||||
0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 };
|
||||
|
||||
static const guint8 PBAP_TARGET[TARGET_SIZE] = {
|
||||
0x79, 0x61, 0x35, 0xF0, 0xF0, 0xC5, 0x11, 0xD8,
|
||||
0x09, 0x66, 0x08, 0x00, 0x20, 0x0C, 0x9A, 0x66 };
|
||||
|
||||
/* Connection ID */
|
||||
static guint32 cid = 0x0000;
|
||||
|
||||
typedef struct {
|
||||
guint8 version;
|
||||
guint8 flags;
|
||||
guint16 mtu;
|
||||
guint8 version;
|
||||
guint8 flags;
|
||||
guint16 mtu;
|
||||
} __attribute__ ((packed)) obex_connect_hdr_t;
|
||||
|
||||
struct obex_commands opp = {
|
||||
.get = opp_get,
|
||||
.chkput = opp_chkput,
|
||||
.put = opp_put,
|
||||
.setpath = NULL,
|
||||
.chkput = opp_chkput,
|
||||
};
|
||||
|
||||
struct obex_commands ftp = {
|
||||
.get = ftp_get,
|
||||
.put = ftp_put,
|
||||
.setpath = ftp_setpath,
|
||||
.chkput = ftp_chkput,
|
||||
.setpath = ftp_setpath,
|
||||
};
|
||||
|
||||
struct obex_commands pbap = {
|
||||
.get = pbap_get,
|
||||
};
|
||||
|
||||
static void os_reset_session(struct obex_session *os)
|
||||
@ -248,7 +255,7 @@ static gboolean chk_cid(obex_t *obex, obex_object_t *obj, guint32 cid)
|
||||
|
||||
os = OBEX_GetUserData(obex);
|
||||
|
||||
/* OPUSH doesn't provide a connection id. */
|
||||
/* Object Push doesn't provide a connection id. */
|
||||
if (os->target == NULL)
|
||||
return TRUE;
|
||||
|
||||
@ -728,7 +735,7 @@ static void obex_event(obex_t *obex, obex_object_t *obj, gint mode,
|
||||
|
||||
switch (evt) {
|
||||
case OBEX_EV_PROGRESS:
|
||||
/* Just emit progress for OPUSH */
|
||||
/* Just emit progress for Object Push */
|
||||
if (os->target == NULL)
|
||||
emit_transfer_progress(os->cid, os->size, os->offset);
|
||||
break;
|
||||
@ -890,7 +897,7 @@ gint obex_session_start(gint fd, struct server *server)
|
||||
|
||||
os = g_new0(struct obex_session, 1);
|
||||
switch (server->service) {
|
||||
case OBEX_OPUSH:
|
||||
case OBEX_OPP:
|
||||
os->target = NULL;
|
||||
os->cmds = &opp;
|
||||
break;
|
||||
@ -898,6 +905,10 @@ gint obex_session_start(gint fd, struct server *server)
|
||||
os->target = FTP_TARGET;
|
||||
os->cmds = &ftp;
|
||||
break;
|
||||
case OBEX_PBAP:
|
||||
os->target = PBAP_TARGET;
|
||||
os->cmds = &pbap;
|
||||
break;
|
||||
default:
|
||||
g_free(os);
|
||||
debug("Invalid OBEX server");
|
||||
|
@ -29,16 +29,18 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define OBEX_OPUSH 0x00
|
||||
#define OBEX_FTP 0x01
|
||||
#define OBEX_OPP 0x01
|
||||
#define OBEX_FTP 0x02
|
||||
#define OBEX_BIP 0x03
|
||||
#define OBEX_PBAP 0x04
|
||||
|
||||
#define OBJECT_SIZE_UNKNOWN -1
|
||||
#define OBJECT_SIZE_DELETE -2
|
||||
|
||||
struct obex_commands {
|
||||
void (*get) (obex_t *obex, obex_object_t *obj);
|
||||
gint (*chkput) (obex_t *obex, obex_object_t *obj);
|
||||
void (*put) (obex_t *obex, obex_object_t *obj);
|
||||
gint (*chkput) (obex_t *obex, obex_object_t *obj);
|
||||
void (*setpath) (obex_t *obex, obex_object_t *obj);
|
||||
};
|
||||
|
||||
@ -73,14 +75,16 @@ struct obex_session {
|
||||
gint obex_session_start(gint fd, struct server *server);
|
||||
gint obex_session_stop();
|
||||
|
||||
gint opp_chkput(obex_t *obex, obex_object_t *obj);
|
||||
void opp_put(obex_t *obex, obex_object_t *obj);
|
||||
void opp_get(obex_t *obex, obex_object_t *obj);
|
||||
void opp_put(obex_t *obex, obex_object_t *obj);
|
||||
gint opp_chkput(obex_t *obex, obex_object_t *obj);
|
||||
|
||||
void ftp_get(obex_t *obex, obex_object_t *obj);
|
||||
void ftp_put(obex_t *obex, obex_object_t *obj);
|
||||
void ftp_setpath(obex_t *obex, obex_object_t *obj);
|
||||
gint ftp_chkput(obex_t *obex, obex_object_t *obj);
|
||||
void ftp_setpath(obex_t *obex, obex_object_t *obj);
|
||||
|
||||
void pbap_get(obex_t *obex, obex_object_t *obj);
|
||||
|
||||
gboolean os_prepare_get(struct obex_session *os, gchar *file, guint32 *size);
|
||||
gint os_prepare_put(struct obex_session *os);
|
||||
|
92
obexd/src/pbap.c
Normal file
92
obexd/src/pbap.c
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
*
|
||||
* OBEX Server
|
||||
*
|
||||
* Copyright (C) 2007-2008 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* 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 <openobex/obex.h>
|
||||
#include <openobex/obex_const.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "phonebook.h"
|
||||
#include "logging.h"
|
||||
#include "obex.h"
|
||||
|
||||
static void test_phonebook(void)
|
||||
{
|
||||
struct phonebook_context *context;
|
||||
struct phonebook_driver *driver;
|
||||
|
||||
driver = phonebook_get_driver(NULL);
|
||||
if (driver == NULL)
|
||||
return;
|
||||
|
||||
context = phonebook_create(driver);
|
||||
if (context == NULL)
|
||||
return;
|
||||
|
||||
phonebook_pullphonebook(context);
|
||||
|
||||
phonebook_unref(context);
|
||||
}
|
||||
|
||||
void pbap_get(obex_t *obex, obex_object_t *obj)
|
||||
{
|
||||
struct obex_session *os;
|
||||
obex_headerdata_t hv;
|
||||
guint32 size;
|
||||
|
||||
os = OBEX_GetUserData(obex);
|
||||
if (os == NULL)
|
||||
return;
|
||||
|
||||
if (os->name)
|
||||
goto fail;
|
||||
|
||||
if (os->type == NULL)
|
||||
goto fail;
|
||||
|
||||
test_phonebook();
|
||||
size = 0;
|
||||
|
||||
hv.bq4 = size;
|
||||
OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_LENGTH, hv, 4, 0);
|
||||
|
||||
/* Add body header */
|
||||
hv.bs = NULL;
|
||||
if (size == 0)
|
||||
OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY,
|
||||
hv, 0, OBEX_FL_FIT_ONE_PACKET);
|
||||
else
|
||||
OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY,
|
||||
hv, 0, OBEX_FL_STREAM_START);
|
||||
|
||||
OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
|
||||
}
|
Loading…
Reference in New Issue
Block a user