* [PATCH obexd 1/2] Port core daemon to gobex
@ 2011-11-29 9:09 Luiz Augusto von Dentz
2011-11-29 9:09 ` [PATCH obexd 2/2] Remove dependency on OpenOBEX Luiz Augusto von Dentz
2011-11-29 9:20 ` [PATCH obexd 1/2] Port core daemon to gobex Johan Hedberg
0 siblings, 2 replies; 3+ messages in thread
From: Luiz Augusto von Dentz @ 2011-11-29 9:09 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
src/manager.c | 26 +-
src/obex-priv.h | 12 +-
src/obex.c | 1395 ++++++++++++++++++++++---------------------------------
src/server.c | 4 +-
4 files changed, 577 insertions(+), 860 deletions(-)
diff --git a/src/manager.c b/src/manager.c
index b151a21..846f8a0 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -33,7 +33,7 @@
#include <sys/socket.h>
#include <inttypes.h>
-#include <openobex/obex.h>
+#include <gobex.h>
#include "obexd.h"
#include "obex.h"
@@ -381,7 +381,7 @@ void manager_cleanup(void)
void manager_emit_transfer_started(struct obex_session *os)
{
- char *path = g_strdup_printf("/transfer%u", os->cid);
+ char *path = g_strdup_printf("/transfer%u", os->id);
g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
OPENOBEX_MANAGER_INTERFACE, "TransferStarted",
@@ -391,9 +391,9 @@ void manager_emit_transfer_started(struct obex_session *os)
g_free(path);
}
-static void emit_transfer_completed(uint32_t id, gboolean success)
+static void emit_transfer_completed(struct obex_session *os, gboolean success)
{
- char *path = g_strdup_printf("/transfer%u", id);
+ char *path = g_strdup_printf("/transfer%u", os->id);
g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
OPENOBEX_MANAGER_INTERFACE, "TransferCompleted",
@@ -404,10 +404,10 @@ static void emit_transfer_completed(uint32_t id, gboolean success)
g_free(path);
}
-static void emit_transfer_progress(uint32_t id, uint32_t total,
+static void emit_transfer_progress(struct obex_session *os, uint32_t total,
uint32_t transfered)
{
- char *path = g_strdup_printf("/transfer%u", id);
+ char *path = g_strdup_printf("/transfer%u", os->id);
g_dbus_emit_signal(connection, path,
TRANSFER_INTERFACE, "Progress",
@@ -420,7 +420,7 @@ static void emit_transfer_progress(uint32_t id, uint32_t total,
void manager_register_transfer(struct obex_session *os)
{
- char *path = g_strdup_printf("/transfer%u", os->cid);
+ char *path = g_strdup_printf("/transfer%u", os->id);
if (!g_dbus_register_interface(connection, path,
TRANSFER_INTERFACE,
@@ -436,11 +436,11 @@ void manager_register_transfer(struct obex_session *os)
void manager_unregister_transfer(struct obex_session *os)
{
- char *path = g_strdup_printf("/transfer%u", os->cid);
+ char *path = g_strdup_printf("/transfer%u", os->id);
/* Got an error during a transfer. */
if (os->object)
- emit_transfer_completed(os->cid, os->offset == os->size);
+ emit_transfer_completed(os, os->offset == os->size);
g_dbus_unregister_interface(connection, path,
TRANSFER_INTERFACE);
@@ -600,7 +600,7 @@ int manager_request_authorization(struct obex_session *os, int32_t time,
void manager_register_session(struct obex_session *os)
{
- char *path = g_strdup_printf("/session%u", os->cid);
+ char *path = g_strdup_printf("/session%u", GPOINTER_TO_UINT(os));
if (!g_dbus_register_interface(connection, path,
SESSION_INTERFACE,
@@ -621,7 +621,7 @@ void manager_register_session(struct obex_session *os)
void manager_unregister_session(struct obex_session *os)
{
- char *path = g_strdup_printf("/session%u", os->cid);
+ char *path = g_strdup_printf("/session%u", GPOINTER_TO_UINT(os));
g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
OPENOBEX_MANAGER_INTERFACE, "SessionRemoved",
@@ -636,13 +636,13 @@ void manager_unregister_session(struct obex_session *os)
void manager_emit_transfer_progress(struct obex_session *os)
{
- emit_transfer_progress(os->cid, os->size, os->offset);
+ emit_transfer_progress(os, os->size, os->offset);
}
void manager_emit_transfer_completed(struct obex_session *os)
{
if (os->object)
- emit_transfer_completed(os->cid, !os->aborted);
+ emit_transfer_completed(os, !os->aborted);
}
DBusConnection *manager_dbus_get_connection(void)
diff --git a/src/obex-priv.h b/src/obex-priv.h
index 6a439b4..ee03bf4 100644
--- a/src/obex-priv.h
+++ b/src/obex-priv.h
@@ -24,9 +24,7 @@
struct obex_session {
GIOChannel *io;
- uint32_t cid;
- uint16_t tx_mtu;
- uint16_t rx_mtu;
+ uint32_t id;
uint8_t cmd;
uint8_t action_id;
char *name;
@@ -36,8 +34,9 @@ struct obex_session {
time_t time;
uint8_t *apparam;
size_t apparam_len;
- uint8_t *nonhdr;
+ const void *nonhdr;
size_t nonhdr_len;
+ guint get_rsp;
uint8_t *buf;
int64_t pending;
int64_t offset;
@@ -48,11 +47,8 @@ struct obex_session {
void *service_data;
struct obex_server *server;
gboolean checked;
- obex_t *obex;
- obex_object_t *obj;
+ GObex *obex;
struct obex_mime_type_driver *driver;
- gboolean stream_open;
- gboolean stream_suspended;
gboolean headers_sent;
};
diff --git a/src/obex.c b/src/obex.c
index a88306d..6307eaa 100644
--- a/src/obex.c
+++ b/src/obex.c
@@ -37,10 +37,10 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <glib.h>
-
-#include <openobex/obex.h>
+#include <gobex/gobex.h>
#include "obexd.h"
#include "log.h"
@@ -53,17 +53,6 @@
#include "transport.h"
#include "btio.h"
-#ifndef OBEX_CMD_ACTION
-#define OBEX_CMD_ACTION 0x06
-#define OBEX_HDR_ACTION_ID 0x94
-#define OBEX_HDR_DESTNAME 0x15
-#define OBEX_HDR_PERMISSIONS 0xD6
-#endif /* OBEX_CMD_ACTION */
-
-/* Default MTU's */
-#define DEFAULT_RX_MTU 32767
-#define DEFAULT_TX_MTU 32767
-
/* Challenge request */
#define NONCE_TAG 0x00
#define OPTIONS_TAG 0x01 /* Optional */
@@ -76,9 +65,6 @@
#define USER_ID_TAG 0x01 /* Optional */
#define DIGEST_NONCE_TAG 0x02 /* Optional */
-/* Connection ID */
-static uint32_t cid = 0x0000;
-
static GSList *sessions = NULL;
typedef struct {
@@ -93,51 +79,19 @@ struct auth_header {
uint8_t val[0];
} __attribute__ ((packed));
-static struct {
- int evt;
- const char *name;
-} obex_event[] = {
- /* Progress has been made */
- { OBEX_EV_PROGRESS, "PROGRESS" },
- /* An incoming request is about to come */
- { OBEX_EV_REQHINT, "REQHINT" },
- /* An incoming request has arrived */
- { OBEX_EV_REQ, "REQ" },
- /* Request has finished */
- { OBEX_EV_REQDONE, "REQDONE" },
- /* Link has been disconnected */
- { OBEX_EV_LINKERR, "LINKERR" },
- /* Malformed data encountered */
- { OBEX_EV_PARSEERR, "PARSEERR" },
- /* Connection accepted */
- { OBEX_EV_ACCEPTHINT, "ACCEPTHINT" },
- /* Request was aborted */
- { OBEX_EV_ABORT, "ABORT" },
- /* Need to feed more data when sending a stream */
- { OBEX_EV_STREAMEMPTY, "STREAMEMPTY" },
- /* Time to pick up data when receiving a stream */
- { OBEX_EV_STREAMAVAIL, "STREAMAVAIL" },
- /* Unexpected data, not fatal */
- { OBEX_EV_UNEXPECTED, "UNEXPECTED" },
- /* First packet of an incoming request has been parsed */
- { OBEX_EV_REQCHECK, "REQCHECK" },
- { 0xFF, NULL },
-};
-
/* Possible commands */
static struct {
int cmd;
const char *name;
} obex_command[] = {
- { OBEX_CMD_CONNECT, "CONNECT" },
- { OBEX_CMD_DISCONNECT, "DISCONNECT" },
- { OBEX_CMD_PUT, "PUT" },
- { OBEX_CMD_GET, "GET" },
- { OBEX_CMD_SETPATH, "SETPATH" },
- { OBEX_CMD_SESSION, "SESSION" },
- { OBEX_CMD_ABORT, "ABORT" },
- { OBEX_CMD_ACTION, "ACTION" },
- { OBEX_FINAL, "FINAL" },
+ { G_OBEX_OP_CONNECT, "CONNECT" },
+ { G_OBEX_OP_DISCONNECT, "DISCONNECT" },
+ { G_OBEX_OP_PUT, "PUT" },
+ { G_OBEX_OP_GET, "GET" },
+ { G_OBEX_OP_SETPATH, "SETPATH" },
+ { G_OBEX_OP_SESSION, "SESSION" },
+ { G_OBEX_OP_ABORT, "ABORT" },
+ { G_OBEX_OP_ACTION, "ACTION" },
{ 0xFF, NULL },
};
@@ -146,70 +100,61 @@ static struct {
int rsp;
const char *name;
} obex_response[] = {
- { OBEX_RSP_CONTINUE, "CONTINUE" },
- { OBEX_RSP_SWITCH_PRO, "SWITCH_PRO" },
- { OBEX_RSP_SUCCESS, "SUCCESS" },
- { OBEX_RSP_CREATED, "CREATED" },
- { OBEX_RSP_ACCEPTED, "ACCEPTED" },
- { OBEX_RSP_NON_AUTHORITATIVE, "NON_AUTHORITATIVE" },
- { OBEX_RSP_NO_CONTENT, "NO_CONTENT" },
- { OBEX_RSP_RESET_CONTENT, "RESET_CONTENT" },
- { OBEX_RSP_PARTIAL_CONTENT, "PARTIAL_CONTENT" },
- { OBEX_RSP_MULTIPLE_CHOICES, "MULTIPLE_CHOICES" },
- { OBEX_RSP_MOVED_PERMANENTLY, "MOVED_PERMANENTLY" },
- { OBEX_RSP_MOVED_TEMPORARILY, "MOVED_TEMPORARILY" },
- { OBEX_RSP_SEE_OTHER, "SEE_OTHER" },
- { OBEX_RSP_NOT_MODIFIED, "NOT_MODIFIED" },
- { OBEX_RSP_USE_PROXY, "USE_PROXY" },
- { OBEX_RSP_BAD_REQUEST, "BAD_REQUEST" },
- { OBEX_RSP_UNAUTHORIZED, "UNAUTHORIZED" },
- { OBEX_RSP_PAYMENT_REQUIRED, "PAYMENT_REQUIRED" },
- { OBEX_RSP_FORBIDDEN, "FORBIDDEN" },
- { OBEX_RSP_NOT_FOUND, "NOT_FOUND" },
- { OBEX_RSP_METHOD_NOT_ALLOWED, "METHOD_NOT_ALLOWED" },
- { OBEX_RSP_NOT_ACCEPTABLE, "NOT_ACCEPTABLE" },
- { OBEX_RSP_PROXY_AUTH_REQUIRED, "PROXY_AUTH_REQUIRED" },
- { OBEX_RSP_REQUEST_TIME_OUT, "REQUEST_TIME_OUT" },
- { OBEX_RSP_CONFLICT, "CONFLICT" },
- { OBEX_RSP_GONE, "GONE" },
- { OBEX_RSP_LENGTH_REQUIRED, "LENGTH_REQUIRED" },
- { OBEX_RSP_PRECONDITION_FAILED, "PRECONDITION_FAILED" },
- { OBEX_RSP_REQ_ENTITY_TOO_LARGE, "REQ_ENTITY_TOO_LARGE" },
- { OBEX_RSP_REQ_URL_TOO_LARGE, "REQ_URL_TOO_LARGE" },
- { OBEX_RSP_UNSUPPORTED_MEDIA_TYPE, "UNSUPPORTED_MEDIA_TYPE"},
- { OBEX_RSP_INTERNAL_SERVER_ERROR, "INTERNAL_SERVER_ERROR" },
- { OBEX_RSP_NOT_IMPLEMENTED, "NOT_IMPLEMENTED" },
- { OBEX_RSP_BAD_GATEWAY, "BAD_GATEWAY" },
- { OBEX_RSP_SERVICE_UNAVAILABLE, "SERVICE_UNAVAILABLE" },
- { OBEX_RSP_GATEWAY_TIMEOUT, "GATEWAY_TIMEOUT" },
- { OBEX_RSP_VERSION_NOT_SUPPORTED, "VERSION_NOT_SUPPORTED" },
- { OBEX_RSP_DATABASE_FULL, "DATABASE_FULL" },
- { OBEX_RSP_DATABASE_LOCKED, "DATABASE_LOCKED" },
+ { G_OBEX_RSP_CONTINUE, "CONTINUE" },
+ { G_OBEX_RSP_SUCCESS, "SUCCESS" },
+ { G_OBEX_RSP_CREATED, "CREATED" },
+ { G_OBEX_RSP_ACCEPTED, "ACCEPTED" },
+ { G_OBEX_RSP_NON_AUTHORITATIVE, "NON_AUTHORITATIVE" },
+ { G_OBEX_RSP_NO_CONTENT, "NO_CONTENT" },
+ { G_OBEX_RSP_RESET_CONTENT, "RESET_CONTENT" },
+ { G_OBEX_RSP_PARTIAL_CONTENT, "PARTIAL_CONTENT" },
+ { G_OBEX_RSP_MULTIPLE_CHOICES, "MULTIPLE_CHOICES" },
+ { G_OBEX_RSP_MOVED_PERMANENTLY, "MOVED_PERMANENTLY" },
+ { G_OBEX_RSP_MOVED_TEMPORARILY, "MOVED_TEMPORARILY" },
+ { G_OBEX_RSP_SEE_OTHER, "SEE_OTHER" },
+ { G_OBEX_RSP_NOT_MODIFIED, "NOT_MODIFIED" },
+ { G_OBEX_RSP_USE_PROXY, "USE_PROXY" },
+ { G_OBEX_RSP_BAD_REQUEST, "BAD_REQUEST" },
+ { G_OBEX_RSP_UNAUTHORIZED, "UNAUTHORIZED" },
+ { G_OBEX_RSP_PAYMENT_REQUIRED, "PAYMENT_REQUIRED" },
+ { G_OBEX_RSP_FORBIDDEN, "FORBIDDEN" },
+ { G_OBEX_RSP_NOT_FOUND, "NOT_FOUND" },
+ { G_OBEX_RSP_METHOD_NOT_ALLOWED, "METHOD_NOT_ALLOWED" },
+ { G_OBEX_RSP_NOT_ACCEPTABLE, "NOT_ACCEPTABLE" },
+ { G_OBEX_RSP_PROXY_AUTH_REQUIRED, "PROXY_AUTH_REQUIRED" },
+ { G_OBEX_RSP_REQUEST_TIME_OUT, "REQUEST_TIME_OUT" },
+ { G_OBEX_RSP_CONFLICT, "CONFLICT" },
+ { G_OBEX_RSP_GONE, "GONE" },
+ { G_OBEX_RSP_LENGTH_REQUIRED, "LENGTH_REQUIRED" },
+ { G_OBEX_RSP_PRECONDITION_FAILED, "PRECONDITION_FAILED" },
+ { G_OBEX_RSP_REQ_ENTITY_TOO_LARGE, "REQ_ENTITY_TOO_LARGE" },
+ { G_OBEX_RSP_REQ_URL_TOO_LARGE, "REQ_URL_TOO_LARGE" },
+ { G_OBEX_RSP_UNSUPPORTED_MEDIA_TYPE, "UNSUPPORTED_MEDIA_TYPE"},
+ { G_OBEX_RSP_INTERNAL_SERVER_ERROR, "INTERNAL_SERVER_ERROR" },
+ { G_OBEX_RSP_NOT_IMPLEMENTED, "NOT_IMPLEMENTED" },
+ { G_OBEX_RSP_BAD_GATEWAY, "BAD_GATEWAY" },
+ { G_OBEX_RSP_SERVICE_UNAVAILABLE, "SERVICE_UNAVAILABLE" },
+ { G_OBEX_RSP_GATEWAY_TIMEOUT, "GATEWAY_TIMEOUT" },
+ { G_OBEX_RSP_VERSION_NOT_SUPPORTED, "VERSION_NOT_SUPPORTED" },
+ { G_OBEX_RSP_DATABASE_FULL, "DATABASE_FULL" },
+ { G_OBEX_RSP_DATABASE_LOCKED, "DATABASE_LOCKED" },
{ 0xFF, NULL },
};
-static void print_event(int evt, int cmd, int rsp)
+static gboolean handle_async_io(void *object, int flags, int err,
+ void *user_data);
+
+static void print_event(int cmd, int rsp)
{
- const char *evtstr = NULL, *cmdstr = NULL, *rspstr = NULL;
+ const char *cmdstr = NULL, *rspstr = NULL;
int i;
- static int lastevt, lastcmd;
-
- if (evt < 0)
- evt = lastevt;
- else
- lastevt = evt;
+ static int lastcmd;
if (cmd < 0)
cmd = lastcmd;
else
lastcmd = cmd;
- for (i = 0; obex_event[i].evt != 0xFF; i++) {
- if (obex_event[i].evt != evt)
- continue;
- evtstr = obex_event[i].name;
- }
-
for (i = 0; obex_command[i].cmd != 0xFF; i++) {
if (obex_command[i].cmd != cmd)
continue;
@@ -222,54 +167,44 @@ static void print_event(int evt, int cmd, int rsp)
rspstr = obex_response[i].name;
}
- obex_debug("%s(0x%x), %s(0x%x), %s(0x%x)", evtstr, evt, cmdstr, cmd,
- rspstr, rsp);
+ obex_debug("%s(0x%x), %s(0x%x)", cmdstr, cmd, rspstr, rsp);
}
-static void os_set_response(obex_object_t *obj, int err)
+static void os_set_response(struct obex_session *os, int err)
{
uint8_t rsp;
- uint8_t lastrsp;
switch (err) {
case 0:
- rsp = OBEX_RSP_CONTINUE;
- lastrsp = OBEX_RSP_SUCCESS;
+ rsp = G_OBEX_RSP_SUCCESS;
break;
case -EPERM:
case -EACCES:
- rsp = OBEX_RSP_FORBIDDEN;
- lastrsp = OBEX_RSP_FORBIDDEN;
+ rsp = G_OBEX_RSP_FORBIDDEN;
break;
case -ENOENT:
- rsp = OBEX_RSP_NOT_FOUND;
- lastrsp = OBEX_RSP_NOT_FOUND;
+ rsp = G_OBEX_RSP_NOT_FOUND;
break;
case -EBADR:
- rsp = OBEX_RSP_BAD_REQUEST;
- lastrsp = OBEX_RSP_BAD_REQUEST;
+ rsp = G_OBEX_RSP_BAD_REQUEST;
break;
case -EFAULT:
- rsp = OBEX_RSP_SERVICE_UNAVAILABLE;
- lastrsp = OBEX_RSP_SERVICE_UNAVAILABLE;
+ rsp = G_OBEX_RSP_SERVICE_UNAVAILABLE;
break;
case -EINVAL:
- rsp = OBEX_RSP_NOT_IMPLEMENTED;
- lastrsp = OBEX_RSP_NOT_IMPLEMENTED;
+ rsp = G_OBEX_RSP_NOT_IMPLEMENTED;
break;
case -ENOTEMPTY:
case -EEXIST:
- rsp = OBEX_RSP_PRECONDITION_FAILED;
- lastrsp = OBEX_RSP_PRECONDITION_FAILED;
+ rsp = G_OBEX_RSP_PRECONDITION_FAILED;
break;
default:
- rsp = OBEX_RSP_INTERNAL_SERVER_ERROR;
- lastrsp = OBEX_RSP_INTERNAL_SERVER_ERROR;
+ rsp = G_OBEX_RSP_INTERNAL_SERVER_ERROR;
}
- print_event(-1, -1, rsp);
+ print_event(-1, rsp);
- OBEX_ObjectSetRsp(obj, rsp, lastrsp);
+ g_obex_send_rsp(os->obex, rsp, NULL, G_OBEX_HDR_INVALID);
}
static void os_session_mark_aborted(struct obex_session *os)
@@ -288,7 +223,7 @@ static void os_reset_session(struct obex_session *os)
if (os->object) {
os->driver->set_io_watch(os->object, NULL, NULL);
os->driver->close(os->object);
- if (os->aborted && os->cmd == OBEX_CMD_PUT && os->path &&
+ if (os->aborted && os->cmd == G_OBEX_OP_PUT && os->path &&
os->driver->remove)
os->driver->remove(os->path);
}
@@ -318,16 +253,18 @@ static void os_reset_session(struct obex_session *os)
os->apparam_len = 0;
}
+ if (os->get_rsp > 0) {
+ g_obex_remove_request_function(os->obex, os->get_rsp);
+ os->get_rsp = 0;
+ }
+
os->object = NULL;
- os->obj = NULL;
os->driver = NULL;
os->aborted = FALSE;
os->pending = 0;
os->offset = 0;
os->size = OBJECT_SIZE_DELETE;
os->headers_sent = FALSE;
- os->stream_open = FALSE;
- os->stream_suspended = FALSE;
}
static void obex_session_free(struct obex_session *os)
@@ -337,6 +274,9 @@ static void obex_session_free(struct obex_session *os)
if (os->io)
g_io_channel_unref(os->io);
+ if (os->obex)
+ g_obex_unref(os->obex);
+
g_free(os);
}
@@ -434,195 +374,131 @@ static uint8_t *challenge_response(const uint8_t *nonce)
return result;
}
-static void cmd_connect(struct obex_session *os,
- obex_t *obex, obex_object_t *obj)
+static void parse_service(struct obex_session *os, GObexPacket *req)
{
- obex_connect_hdr_t *nonhdr;
- obex_headerdata_t hd;
- uint8_t *buffer;
- unsigned int hlen, newsize;
- uint16_t mtu;
- uint8_t hi;
- const uint8_t *target = NULL, *who = NULL, *nonce = NULL;
- unsigned int target_size = 0, who_size = 0;
- int err;
+ GObexHeader *hdr;
+ const guint8 *target = NULL, *who = NULL;
+ gsize target_size = 0, who_size = 0;
- if (OBEX_ObjectGetNonHdrData(obj, &buffer) != sizeof(*nonhdr)) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
- DBG("Invalid OBEX CONNECT packet");
- return;
- }
-
- nonhdr = (obex_connect_hdr_t *) buffer;
- mtu = g_ntohs(nonhdr->mtu);
- DBG("Version: 0x%02x. Flags: 0x%02x OBEX packet length: %d",
- nonhdr->version, nonhdr->flags, mtu);
- /* Leave space for headers */
- newsize = mtu - 200;
-
- os->tx_mtu = newsize;
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_WHO);
+ if (hdr == NULL)
+ goto target;
- DBG("Resizing stream chunks to %d", newsize);
+ g_obex_header_get_bytes(hdr, &who, &who_size);
- /* connection id will be used to track the sessions, even for OPP */
- os->cid = ++cid;
+target:
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TARGET);
+ if (hdr == NULL)
+ goto probe;
- while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) {
- switch (hi) {
- case OBEX_HDR_WHO:
- who = hd.bs;
- who_size = hlen;
- break;
- case OBEX_HDR_TARGET:
- target = hd.bs;
- target_size = hlen;
- break;
- case OBEX_HDR_AUTHCHAL:
- if (nonce) {
- DBG("Ignoring multiple challenge headers");
- break;
- }
-
- nonce = extract_nonce(hd.bs, hlen);
- DBG("AUTH CHALLENGE REQUEST");
- break;
- }
- }
+ g_obex_header_get_bytes(hdr, &target, &target_size);
+probe:
os->service = obex_service_driver_find(os->server->drivers,
target, target_size,
who, who_size);
- if (os->service == NULL) {
- error("Connect attempt to a non-supported target");
- OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
+}
+static void parse_authchal(struct obex_session *session, GObexPacket *req,
+ GObexPacket *rsp)
+{
+ GObexHeader *hdr;
+ const guint8 *data, *nonce = NULL;
+ gsize len;
+ uint8_t challenge[18];
+ struct auth_header *auth = (struct auth_header *) challenge;
+ uint8_t *response;
+
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_AUTHCHAL);
+ if (hdr == NULL)
return;
- }
- DBG("Selected driver: %s", os->service->name);
-
- if (!os->service->connect) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
+ if (!g_obex_header_get_bytes(hdr, &data, &len))
return;
- }
-
- os->service_data = os->service->connect(os, &err);
- if (err == 0 && os->service->target) {
- hd.bs = os->service->target;
- OBEX_ObjectAddHeader(obex, obj,
- OBEX_HDR_WHO, hd, os->service->target_size,
- OBEX_FL_FIT_ONE_PACKET);
- hd.bq4 = os->cid;
- OBEX_ObjectAddHeader(obex, obj,
- OBEX_HDR_CONNECTION, hd, 4,
- OBEX_FL_FIT_ONE_PACKET);
- }
-
- if (err == 0 && nonce) {
- uint8_t challenge[18];
- struct auth_header *hdr = (struct auth_header *) challenge;
- uint8_t *response = challenge_response(nonce);
- hdr->tag = DIGEST_TAG;
- hdr->len = NONCE_LEN;
- memcpy(hdr->val, response, NONCE_LEN);
+ nonce = extract_nonce(data, len);
+ DBG("AUTH CHALLENGE REQUEST");
- g_free(response);
+ response = challenge_response(nonce);
+ auth->tag = DIGEST_TAG;
+ auth->len = NONCE_LEN;
+ memcpy(auth->val, response, NONCE_LEN);
- hd.bs = challenge;
- OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_AUTHRESP, hd, 18, 0);
- }
-
- os_set_response(obj, err);
+ hdr = g_obex_header_new_bytes(G_OBEX_HDR_AUTHRESP, challenge,
+ sizeof(challenge));
+ g_obex_packet_add_header(rsp, hdr);
}
-static gboolean chk_cid(obex_t *obex, obex_object_t *obj, uint32_t cid)
+static void cmd_connect(GObex *obex, GObexPacket *req, void *user_data)
{
- struct obex_session *os;
- obex_headerdata_t hd;
- unsigned int hlen;
- uint8_t hi;
- gboolean ret = FALSE;
+ struct obex_session *os = user_data;
+ GObexPacket *rsp;
+ GObexHeader *hdr;
+ int err;
- os = OBEX_GetUserData(obex);
+ DBG("");
- /* Object Push doesn't provide a connection id. */
- if (os->service->service == OBEX_OPP)
- return TRUE;
+ print_event(G_OBEX_OP_CONNECT, -1);
- while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) {
- if (hi == OBEX_HDR_CONNECTION && hlen == 4) {
- ret = (hd.bq4 == cid ? TRUE : FALSE);
- break;
- }
+ parse_service(os, req);
+
+ if (os->service == NULL || os->service->connect == NULL) {
+ error("Connect attempt to a non-supported target");
+ os_set_response(os, -EPERM);
+ return;
}
- OBEX_ObjectReParseHeaders(obex, obj);
+ DBG("Selected driver: %s", os->service->name);
- if (ret == FALSE)
- OBEX_ObjectSetRsp(obj, OBEX_RSP_SERVICE_UNAVAILABLE,
- OBEX_RSP_SERVICE_UNAVAILABLE);
+ os->service_data = os->service->connect(os, &err);
+ if (err < 0) {
+ os_set_response(os, err);
+ return;
+ }
- return ret;
-}
+ rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
-static int obex_read_stream(struct obex_session *os, obex_t *obex,
- obex_object_t *obj)
-{
- int size;
- ssize_t len = 0;
- const uint8_t *buffer;
+ parse_authchal(os, req, rsp);
- DBG("name=%s type=%s rx_mtu=%d file=%p",
- os->name ? os->name : "", os->type ? os->type : "",
- os->rx_mtu, os->object);
+ if (os->service->target) {
+ hdr = g_obex_header_new_bytes(G_OBEX_HDR_WHO,
+ os->service->target,
+ os->service->target_size);
+ g_obex_packet_add_header(rsp, hdr);
+ }
- if (os->aborted)
- return -EPERM;
+ g_obex_send(obex, rsp, NULL);
- /* workaround: client didn't send the object lenght */
- if (os->size == OBJECT_SIZE_DELETE)
- os->size = OBJECT_SIZE_UNKNOWN;
+ print_event(-1, 0);
+}
- /* If there's something to write and we are able to write it */
- if (os->pending > 0 && os->driver && os->object)
- goto write;
+static void cmd_disconnect(GObex *obex, GObexPacket *req, void *user_data)
+{
+ struct obex_session *os = user_data;
- size = OBEX_ObjectReadStream(obex, obj, &buffer);
- if (size < 0) {
- error("Error on OBEX stream");
- return -EIO;
- }
+ DBG("session %p", os);
- if (size > os->rx_mtu) {
- error("Received more data than RX_MAX");
- return -EIO;
- }
+ print_event(G_OBEX_OP_DISCONNECT, -1);
- os->buf = g_realloc(os->buf, os->pending + size);
- memcpy(os->buf + os->pending, buffer, size);
- os->pending += size;
+ os_set_response(os, 0);
+}
- /* only write if both object and driver are valid */
- if (os->object == NULL || os->driver == NULL) {
- DBG("Stored %" PRIu64 " bytes into temporary buffer",
- os->pending);
- return 0;
- }
+static ssize_t driver_write(struct obex_session *os)
+{
+ ssize_t len = 0;
-write:
while (os->pending > 0) {
ssize_t w;
- w = os->driver->write(os->object, os->buf + len,
- os->pending);
+ w = os->driver->write(os->object, os->buf + len, os->pending);
if (w < 0) {
+ error("write(): %s (%zd)", strerror(-w), -w);
if (w == -EINTR)
continue;
- else {
+ else if (w == -EINVAL)
memmove(os->buf, os->buf + len, os->pending);
- return w;
- }
+
+ return w;
}
len += w;
@@ -630,71 +506,103 @@ write:
os->pending -= w;
}
- return 0;
-}
+ DBG("%zd written", len);
-static int obex_write_stream(struct obex_session *os,
- obex_t *obex, obex_object_t *obj)
-{
- obex_headerdata_t hd;
- ssize_t len;
+ if (os->service->progress != NULL)
+ os->service->progress(os, os->service_data);
- DBG("name=%s type=%s tx_mtu=%d file=%p",
- os->name ? os->name : "", os->type ? os->type : "",
- os->tx_mtu, os->object);
+ return len;
+}
- if (os->aborted)
- return -EPERM;
+static gssize driver_read(struct obex_session *os, void *buf, gsize size)
+{
+ gssize len;
if (os->object == NULL)
return -EIO;
- len = os->driver->read(os->object, os->buf, os->tx_mtu);
+ if (os->service->progress != NULL)
+ os->service->progress(os, os->service_data);
+
+ len = os->driver->read(os->object, buf, size);
if (len < 0) {
error("read(): %s (%zd)", strerror(-len), -len);
+ if (len == -ENOSTR)
+ return 0;
if (len == -EAGAIN)
- return len;
+ os->driver->set_io_watch(os->object, handle_async_io,
+ os);
+ }
- g_free(os->buf);
- os->buf = NULL;
+ os->offset += len;
- if (len == -ENOSTR)
- return 0;
+ DBG("%zd read", len);
- return len;
- }
+ return len;
+}
+
+static gssize send_data(void *buf, gsize size, gpointer user_data)
+{
+ struct obex_session *os = user_data;
+
+ DBG("name=%s type=%s file=%p size=%zu", os->name, os->type, os->object,
+ size);
- if (!os->stream_open) {
- hd.bs = NULL;
- OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, 0,
- OBEX_FL_STREAM_START);
- os->stream_open = TRUE;
+ if (os->aborted)
+ return -EPERM;
+
+ return driver_read(os, buf, size);
+}
+
+static void transfer_complete(GObex *obex, GError *err, gpointer user_data)
+{
+ struct obex_session *os = user_data;
+
+ DBG("");
+
+ if (err != NULL) {
+ error("transfer failed: %s\n", err->message);
+ return;
}
- if (len == 0) {
- hd.bs = NULL;
- OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, 0,
- OBEX_FL_STREAM_DATAEND);
- g_free(os->buf);
- os->buf = NULL;
+ if (os->object && os->driver && os->driver->flush) {
+ if (os->driver->flush(os->object) == -EAGAIN) {
+ g_obex_suspend(os->obex);
+ os->driver->set_io_watch(os->object, handle_async_io,
+ os);
+ }
}
+}
- hd.bs = os->buf;
- OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, len,
- OBEX_FL_STREAM_DATA);
+static void cmd_get_rsp(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+ struct obex_session *os = user_data;
- return 0;
+ DBG("");
+
+ print_event(G_OBEX_OP_GET, -1);
+
+ if (os->size != OBJECT_SIZE_UNKNOWN && os->size < UINT32_MAX)
+ g_obex_get_rsp(os->obex, send_data, transfer_complete,
+ os, NULL,
+ G_OBEX_HDR_LENGTH, os->size,
+ G_OBEX_HDR_INVALID);
+ else
+ g_obex_get_rsp(os->obex, send_data, transfer_complete,
+ os, NULL,
+ G_OBEX_HDR_INVALID);
+
+ print_event(G_OBEX_OP_GET, G_OBEX_RSP_CONTINUE);
}
-static int obex_write(struct obex_session *os, obex_t *obex, obex_object_t *obj)
+static gssize driver_get_headers(struct obex_session *os)
{
- obex_headerdata_t hd;
- ssize_t len;
- uint8_t hi;
+ GObexPacket *rsp;
+ gssize len, total = 0;
+ guint8 data[255];
+ guint8 id;
- DBG("name=%s type=%s tx_mtu=%d file=%p",
- os->name ? os->name : "", os->type ? os->type : "",
- os->tx_mtu, os->object);
+ DBG("name=%s type=%s object=%p", os->name, os->type, os->object);
if (os->aborted)
return -EPERM;
@@ -703,17 +611,24 @@ static int obex_write(struct obex_session *os, obex_t *obex, obex_object_t *obj)
return -EIO;
if (os->headers_sent)
- return obex_write_stream(os, obex, obj);
+ return 0;
+
+ if (os->driver->get_next_header == NULL) {
+ os->headers_sent = TRUE;
+ return 0;
+ }
- if (!os->driver->get_next_header)
- goto skip;
+ rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
+ while ((len = os->driver->get_next_header(os->object, &data,
+ sizeof(data), &id))) {
+ GObexHeader *hdr;
- while ((len = os->driver->get_next_header(os->object, os->buf,
- os->tx_mtu, &hi)) != 0) {
if (len < 0) {
error("get_next_header(): %s (%zd)", strerror(-len),
-len);
+ g_obex_packet_free(rsp);
+
if (len == -EAGAIN)
return len;
@@ -723,218 +638,231 @@ static int obex_write(struct obex_session *os, obex_t *obex, obex_object_t *obj)
return len;
}
- hd.bs = os->buf;
- OBEX_ObjectAddHeader(obex, obj, hi, hd, len, 0);
+ hdr = g_obex_header_new_bytes(id, data, len);
+ g_obex_packet_add_header(rsp, hdr);
+ total += len;
}
-skip:
+ if (total == 0) {
+ g_obex_packet_free(rsp);
+ return 0;
+ }
+
+ g_obex_send(os->obex, rsp, NULL);
+
+ os->get_rsp = g_obex_add_request_function(os->obex, G_OBEX_OP_GET,
+ cmd_get_rsp, os);
+
os->headers_sent = TRUE;
- return obex_write_stream(os, obex, obj);
+ print_event(-1, G_OBEX_RSP_CONTINUE);
+
+ return total;
}
static gboolean handle_async_io(void *object, int flags, int err,
void *user_data)
{
struct obex_session *os = user_data;
- int ret = 0;
- if (err < 0) {
- ret = err;
- goto proceed;
- }
-
- if (flags & (G_IO_IN | G_IO_PRI))
- ret = obex_write(os, os->obex, os->obj);
- else if ((flags & G_IO_OUT) && os->pending > 0)
- ret = obex_read_stream(os, os->obex, os->obj);
+ if (err < 0)
+ goto done;
-proceed:
- os->stream_suspended = FALSE;
+ if (flags & G_IO_OUT)
+ err = driver_write(os);
+ if ((flags & G_IO_IN) && !os->headers_sent)
+ err = driver_get_headers(os);
- if (ret == -EAGAIN) {
+ if (err == -EAGAIN)
return TRUE;
- } else if (ret < 0) {
- os_set_response(os->obj, ret);
- OBEX_CancelRequest(os->obex, TRUE);
- } else {
- OBEX_ResumeRequest(os->obex);
- }
- return os->stream_suspended;
+done:
+ if (err < 0)
+ os_set_response(os, err);
+
+ g_obex_resume(os->obex);
+
+ return FALSE;
}
-static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj)
+static gboolean recv_data(const void *buf, gsize size, gpointer user_data)
{
- obex_headerdata_t hd;
- unsigned int hlen;
- uint8_t hi;
- int err;
+ struct obex_session *os = user_data;
+ ssize_t ret;
- if (!os->service) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
- return;
- } else if (!os->service->get) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
- OBEX_RSP_NOT_IMPLEMENTED);
- return;
+ DBG("name=%s type=%s file=%p size=%zu", os->name, os->type, os->object,
+ size);
+
+ if (os->aborted)
+ return FALSE;
+
+ /* workaround: client didn't send the object lenght */
+ if (os->size == OBJECT_SIZE_DELETE)
+ os->size = OBJECT_SIZE_UNKNOWN;
+
+ os->buf = g_realloc(os->buf, os->pending + size);
+ memcpy(os->buf + os->pending, buf, size);
+ os->pending += size;
+
+ /* only write if both object and driver are valid */
+ if (os->object == NULL || os->driver == NULL) {
+ DBG("Stored %" PRIu64 " bytes into temporary buffer",
+ os->pending);
+ return TRUE;
}
- g_return_if_fail(chk_cid(obex, obj, os->cid));
+ ret = driver_write(os);
+ if (ret >= 0)
+ return TRUE;
- os->headers_sent = FALSE;
- os->stream_open = FALSE;
+ if (ret == -EAGAIN) {
+ g_obex_suspend(os->obex);
+ os->driver->set_io_watch(os->object, handle_async_io, os);
+ return TRUE;
+ }
- while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) {
- switch (hi) {
- case OBEX_HDR_NAME:
- if (os->name) {
- DBG("Ignoring multiple name headers");
- break;
- }
+ return FALSE;
+}
- if (hlen == 0)
- continue;
+static void parse_type(struct obex_session *os, GObexPacket *req)
+{
+ GObexHeader *hdr;
+ const guint8 *type;
+ gsize len;
- os->name = g_convert((const char *) hd.bs, hlen,
- "UTF8", "UTF16BE", NULL, NULL, NULL);
- DBG("OBEX_HDR_NAME: %s", os->name);
- break;
- case OBEX_HDR_TYPE:
- if (os->type) {
- DBG("Ignoring multiple type headers");
- break;
- }
+ g_free(os->type);
+ os->type = NULL;
- if (hlen == 0)
- continue;
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TYPE);
+ if (hdr == NULL)
+ goto probe;
- /* Ensure null termination */
- if (hd.bs[hlen - 1] != '\0')
- break;
+ if (!g_obex_header_get_bytes(hdr, &type, &len))
+ goto probe;
- if (!g_utf8_validate((const char *) hd.bs, -1, NULL)) {
- DBG("Invalid type header: %s", hd.bs);
- break;
- }
+ /* Ensure null termination */
+ if (type[len - 1] != '\0')
+ goto probe;
- /* FIXME: x-obex/folder-listing - type is mandatory */
+ os->type = g_strndup((const char *) type, len);
+ DBG("TYPE: %s", os->type);
- os->type = g_strndup((const char *) hd.bs, hlen);
- DBG("OBEX_HDR_TYPE: %s", os->type);
- os->driver = obex_mime_type_driver_find(
- os->service->target,
+probe:
+ os->driver = obex_mime_type_driver_find(os->service->target,
os->service->target_size,
os->type,
os->service->who,
os->service->who_size);
- break;
- }
+}
- if (hi == OBEX_HDR_APPARAM) {
- os->apparam = g_memdup(hd.bs, hlen);
- os->apparam_len = hlen;
- }
- }
+static void parse_name(struct obex_session *os, GObexPacket *req)
+{
+ GObexHeader *hdr;
+ const char *name;
- if (os->type == NULL)
- os->driver = obex_mime_type_driver_find(os->service->target,
- os->service->target_size,
- NULL,
- os->service->who,
- os->service->who_size);
+ g_free(os->name);
+ os->name = NULL;
- if (!os->driver) {
- error("No driver found");
- OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
- OBEX_RSP_NOT_IMPLEMENTED);
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_NAME);
+ if (hdr == NULL)
return;
- }
- err = os->service->get(os, os->service_data);
+ if (!g_obex_header_get_unicode(hdr, &name))
+ return;
- if (err < 0)
- goto done;
+ os->name = g_strdup(name);
+ DBG("NAME: %s", os->name);
+}
- if (os->size != OBJECT_SIZE_UNKNOWN && os->size < UINT32_MAX) {
- hd.bq4 = os->size;
- OBEX_ObjectAddHeader(obex, obj,
- OBEX_HDR_LENGTH, hd, 4, 0);
- }
+static void parse_apparam(struct obex_session *os, GObexPacket *req)
+{
+ GObexHeader *hdr;
+ const guint8 *apparam;
+ gsize len;
- /* Add body header */
- hd.bs = NULL;
- if (os->size == 0) {
- OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, 0,
- OBEX_FL_FIT_ONE_PACKET);
- goto done;
- }
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_APPARAM);
+ if (hdr == NULL)
+ return;
- /* Try to write to stream and suspend the stream immediately
- * if no data available to send. */
- err = obex_write(os, obex, obj);
- if (err == -EAGAIN) {
- OBEX_SuspendRequest(obex, obj);
- os->obj = obj;
- os->driver->set_io_watch(os->object, handle_async_io, os);
+ if (!g_obex_header_get_bytes(hdr, &apparam, &len))
return;
- }
-done:
- os_set_response(obj, err);
+ os->apparam = g_memdup(apparam, len);
+ os->apparam_len = len;
+ DBG("APPARAM");
}
-static void cmd_setpath(struct obex_session *os,
- obex_t *obex, obex_object_t *obj)
+static void cmd_get(GObex *obex, GObexPacket *req, gpointer user_data)
{
- obex_headerdata_t hd;
- uint32_t hlen;
+ struct obex_session *os = user_data;
int err;
- uint8_t hi;
- if (!os->service) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
+ DBG("session %p", os);
+
+ print_event(G_OBEX_OP_GET, -1);
+
+ if (os->service == NULL) {
+ os_set_response(os, -EPERM);
return;
- } else if (!os->service->setpath) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
- OBEX_RSP_NOT_IMPLEMENTED);
+ }
+
+ if (os->service->get == NULL) {
+ os_set_response(os, -EINVAL);
return;
}
- g_return_if_fail(chk_cid(obex, obj, os->cid));
+ os->headers_sent = FALSE;
- if (os->name) {
- g_free(os->name);
- os->name = NULL;
+ if (os->type) {
+ g_free(os->type);
+ os->type = NULL;
}
- while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) {
- if (hi != OBEX_HDR_NAME)
- continue;
+ parse_type(os, req);
- if (os->name) {
- DBG("Ignoring multiple name headers");
- break;
- }
+ if (!os->driver) {
+ error("No driver found");
+ os_set_response(os, -EINVAL);
+ return;
+ }
- /* This is because OBEX_UnicodeToChar() accesses the string
- * even if its size is zero */
- if (hlen == 0) {
- os->name = g_strdup("");
- break;
- }
+ parse_name(os, req);
- os->name = g_convert((const char *) hd.bs, hlen,
- "UTF8", "UTF16BE", NULL, NULL, NULL);
+ parse_apparam(os, req);
- DBG("Set path name: %s", os->name);
- break;
+ err = os->service->get(os, os->service_data);
+ if (err == 0)
+ return;
+
+ os_set_response(os, err);
+}
+
+static void cmd_setpath(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+ struct obex_session *os = user_data;
+ int err;
+
+ DBG("");
+
+ print_event(G_OBEX_OP_SETPATH, -1);
+
+ if (os->service == NULL) {
+ err = -EPERM;
+ goto done;
+ }
+
+ if (os->service->setpath == NULL) {
+ err = -EINVAL;
+ goto done;
}
- os->nonhdr_len = OBEX_ObjectGetNonHdrData(obj, &os->nonhdr);
+ parse_name(os, req);
+
+ os->nonhdr = g_obex_packet_get_data(req, &os->nonhdr_len);
err = os->service->setpath(os, os->service_data);
- os_set_response(obj, err);
+done:
+ os_set_response(os, err);
}
int obex_get_stream_start(struct obex_session *os, const char *filename)
@@ -954,8 +882,27 @@ int obex_get_stream_start(struct obex_session *os, const char *filename)
os->offset = 0;
os->size = size;
- if (size > 0)
- os->buf = g_malloc0(os->tx_mtu);
+ err = driver_get_headers(os);
+ if (err == -EAGAIN) {
+ g_obex_suspend(os->obex);
+ os->driver->set_io_watch(os->object, handle_async_io, os);
+ return 0;
+ } else if (err < 0) {
+ return err;
+ } else if (err > 0)
+ return 0;
+
+ if (os->size != OBJECT_SIZE_UNKNOWN && os->size < UINT32_MAX)
+ g_obex_get_rsp(os->obex, send_data, transfer_complete,
+ os, NULL,
+ G_OBEX_HDR_LENGTH, os->size,
+ G_OBEX_HDR_INVALID);
+ else
+ g_obex_get_rsp(os->obex, send_data, transfer_complete,
+ os, NULL,
+ G_OBEX_HDR_INVALID);
+
+ print_event(G_OBEX_OP_GET, G_OBEX_RSP_SUCCESS);
return 0;
}
@@ -975,113 +922,49 @@ int obex_put_stream_start(struct obex_session *os, const char *filename)
os->path = g_strdup(filename);
- if (!os->buf) {
- DBG("PUT request checked, no buffered data");
- return 0;
- }
-
- if (os->pending == 0)
- return 0;
-
- return obex_read_stream(os, os->obex, NULL);
+ return 0;
}
-static gboolean check_put(obex_t *obex, obex_object_t *obj)
+static void parse_length(struct obex_session *os, GObexPacket *req)
{
- struct obex_session *os;
- obex_headerdata_t hd;
- unsigned int hlen;
- uint8_t hi;
- int ret;
-
- os = OBEX_GetUserData(obex);
-
- if (os->type) {
- g_free(os->type);
- os->type = NULL;
- }
-
- if (os->name) {
- g_free(os->name);
- os->name = NULL;
- }
-
- while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) {
- switch (hi) {
- case OBEX_HDR_NAME:
- if (os->name) {
- DBG("Ignoring multiple name headers");
- break;
- }
-
- if (hlen == 0)
- continue;
-
- os->name = g_convert((const char *) hd.bs, hlen,
- "UTF8", "UTF16BE", NULL, NULL, NULL);
- DBG("OBEX_HDR_NAME: %s", os->name);
- break;
-
- case OBEX_HDR_TYPE:
- if (os->type) {
- DBG("Ignoring multiple type headers");
- break;
- }
+ GObexHeader *hdr;
+ guint32 size;
- if (hlen == 0)
- continue;
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_LENGTH);
+ if (hdr == NULL)
+ return;
- /* Ensure null termination */
- if (hd.bs[hlen - 1] != '\0')
- break;
+ if (!g_obex_header_get_uint32(hdr, &size))
+ return;
- if (!g_utf8_validate((const char *) hd.bs, -1, NULL)) {
- DBG("Invalid type header: %s", hd.bs);
- break;
- }
+ os->size = size;
+ DBG("LENGTH: %" PRIu64, os->size);
+}
- os->type = g_strndup((const char *) hd.bs, hlen);
- DBG("OBEX_HDR_TYPE: %s", os->type);
- os->driver = obex_mime_type_driver_find(
- os->service->target,
- os->service->target_size,
- os->type,
- os->service->who,
- os->service->who_size);
- break;
+static void parse_time(struct obex_session *os, GObexPacket *req)
+{
+ GObexHeader *hdr;
+ const guint8 *time;
+ gsize len;
- case OBEX_HDR_BODY:
- if (os->size < 0)
- os->size = OBJECT_SIZE_UNKNOWN;
- break;
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TIME);
+ if (hdr == NULL)
+ return;
- case OBEX_HDR_LENGTH:
- os->size = hd.bq4;
- DBG("OBEX_HDR_LENGTH: %" PRIu64, os->size);
- break;
- case OBEX_HDR_TIME:
- os->time = parse_iso8610((const char *) hd.bs, hlen);
- break;
- }
- }
- OBEX_ObjectReParseHeaders(obex, obj);
+ if (!g_obex_header_get_bytes(hdr, &time, &len))
+ return;
- if (os->type == NULL)
- os->driver = obex_mime_type_driver_find(os->service->target,
- os->service->target_size,
- NULL,
- os->service->who,
- os->service->who_size);
+ os->time = parse_iso8610((const char *) time, len);
+ DBG("TIME: %s", ctime(&os->time));
+}
- if (!os->driver) {
- error("No driver found");
- OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
- OBEX_RSP_NOT_IMPLEMENTED);
- return FALSE;
- }
+static gboolean check_put(GObex *obex, GObexPacket *req, void *user_data)
+{
+ struct obex_session *os = user_data;
+ int ret;
- if (!os->service->chkput)
+ if (os->service->chkput == NULL)
goto done;
ret = os->service->chkput(os, os->service_data);
@@ -1089,20 +972,16 @@ static gboolean check_put(obex_t *obex, obex_object_t *obj)
case 0:
break;
case -EAGAIN:
- OBEX_SuspendRequest(obex, obj);
- os->obj = obj;
+ g_obex_suspend(os->obex);
os->driver->set_io_watch(os->object, handle_async_io, os);
return TRUE;
default:
- os_set_response(obj, ret);
+ os_set_response(os, ret);
return FALSE;
-
}
- if (os->size == OBJECT_SIZE_DELETE || os->size == OBJECT_SIZE_UNKNOWN) {
+ if (os->size == OBJECT_SIZE_DELETE || os->size == OBJECT_SIZE_UNKNOWN)
DBG("Got a PUT without a Length");
- goto done;
- }
done:
os->checked = TRUE;
@@ -1110,351 +989,193 @@ done:
return TRUE;
}
-static void cmd_put(struct obex_session *os, obex_t *obex, obex_object_t *obj)
+static void cmd_put(GObex *obex, GObexPacket *req, gpointer user_data)
{
+ struct obex_session *os = user_data;
int err;
- if (!os->service) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
+ DBG("");
+
+ print_event(G_OBEX_OP_PUT, -1);
+
+ if (os->service == NULL) {
+ os_set_response(os, -EPERM);
+ return;
+ }
+
+ parse_type(os, req);
+
+ if (os->driver == NULL) {
+ error("No driver found");
+ os_set_response(os, -EINVAL);
return;
}
- g_return_if_fail(chk_cid(obex, obj, os->cid));
+ parse_name(os, req);
+ parse_length(os, req);
+ parse_time(os, req);
if (!os->checked) {
- if (!check_put(obex, obj))
+ if (!check_put(obex, req, user_data))
return;
}
- if (!os->service->put) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
- OBEX_RSP_NOT_IMPLEMENTED);
+ if (os->service->put == NULL) {
+ os_set_response(os, -EINVAL);
return;
}
err = os->service->put(os, os->service_data);
- if (err < 0) {
- os_set_response(obj, err);
+ if (err == 0) {
+ g_obex_put_rsp(obex, req, recv_data, transfer_complete, os,
+ NULL, G_OBEX_HDR_INVALID);
+ print_event(G_OBEX_OP_PUT, G_OBEX_RSP_CONTINUE);
return;
}
- if (os->object && os->driver && os->driver->flush) {
- err = os->driver->flush(os->object);
- if (err == -EAGAIN) {
- OBEX_SuspendRequest(obex, obj);
- os->obj = obj;
- os->driver->set_io_watch(os->object,
- handle_async_io, os);
- } else if (err < 0) {
- os_set_response(obj, err);
- }
- }
+ os_set_response(os, err);
}
-static void cmd_action(struct obex_session *os, obex_t *obex,
- obex_object_t *obj)
+static void parse_destname(struct obex_session *os, GObexPacket *req)
{
- obex_headerdata_t hd;
- unsigned int hlen;
- uint8_t hi;
- int err;
-
- if (!os->service) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
- return;
- } else if (!os->service->action) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
- OBEX_RSP_NOT_IMPLEMENTED);
- return;
- }
+ GObexHeader *hdr;
+ const char *destname;
- g_return_if_fail(chk_cid(obex, obj, os->cid));
+ g_free(os->destname);
+ os->destname = NULL;
- if (os->name) {
- g_free(os->name);
- os->name = NULL;
- }
-
- if (os->destname) {
- g_free(os->destname);
- os->destname = NULL;
- }
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_DESTNAME);
+ if (hdr == NULL)
+ return;
- while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) {
- switch (hi) {
- case OBEX_HDR_NAME:
- if (os->name) {
- DBG("Ignoring multiple name headers");
- break;
- }
+ if (!g_obex_header_get_unicode(hdr, &destname))
+ return;
- if (hlen == 0)
- continue;
+ os->destname = g_strdup(destname);
+ DBG("DESTNAME: %s", os->destname);
+}
- os->name = g_convert((const char *) hd.bs, hlen,
- "UTF8", "UTF16BE", NULL, NULL, NULL);
- DBG("OBEX_HDR_NAME: %s", os->name);
- break;
+static void parse_action(struct obex_session *os, GObexPacket *req)
+{
+ GObexHeader *hdr;
+ guint8 id;
- case OBEX_HDR_DESTNAME:
- if (os->destname) {
- DBG("Ignoring multiple destination headers");
- break;
- }
+ hdr = g_obex_packet_get_header(req, G_OBEX_HDR_ACTION);
+ if (hdr == NULL)
+ return;
- if (hlen == 0)
- continue;
+ if (!g_obex_header_get_uint8(hdr, &id))
+ return;
- os->destname = g_convert((const char *) hd.bs, hlen,
- "UTF8", "UTF16BE", NULL, NULL, NULL);
- DBG("OBEX_HDR_DESTNAME: %s", os->destname);
- break;
+ os->action_id = id;
+ DBG("ACTION: 0x%02x", os->action_id);
+}
- case OBEX_HDR_ACTION_ID:
- if (hlen == 0)
- continue;
+static void cmd_action(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+ struct obex_session *os = user_data;
+ int err;
- os->action_id = hd.bq1;
+ DBG("");
- DBG("OBEX_HDR_ACTIONID: %u", os->action_id);
- break;
+ print_event(G_OBEX_OP_ACTION, -1);
- case OBEX_HDR_PERMISSIONS:
- if (hlen == 0)
- continue;
+ if (os->service == NULL) {
+ err = -EPERM;
+ goto done;
+ }
- DBG("OBEX_HDR_PERMISSIONS: %d", hd.bq4);
- break;
- }
+ if (os->service->action == NULL) {
+ err = -EINVAL;
+ goto done;
}
+ parse_name(os, req);
+ parse_destname(os, req);
+ parse_action(os, req);
+
os->driver = obex_mime_type_driver_find(os->service->target,
os->service->target_size,
NULL,
os->service->who,
os->service->who_size);
-
- if (!os->driver || !os->service->action) {
- OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
- OBEX_RSP_NOT_IMPLEMENTED);
- return;
+ if (os->driver == NULL) {
+ err = -EINVAL;
+ goto done;
}
err = os->service->action(os, os->service_data);
- if (err < 0) {
- os_set_response(obj, err);
- return;
- }
-
- return;
+done:
+ os_set_response(os, err);
}
-static void obex_event_cb(obex_t *obex, obex_object_t *obj, int mode,
- int evt, int cmd, int rsp)
+static void cmd_abort(GObex *obex, GObexPacket *req, gpointer user_data)
{
- struct obex_session *os;
- int err;
-
- print_event(evt, cmd, rsp);
-
- os = OBEX_GetUserData(obex);
+ struct obex_session *os = user_data;
- switch (evt) {
- case OBEX_EV_PROGRESS:
- if (os->service && os->service->progress)
- os->service->progress(os, os->service_data);
- break;
- case OBEX_EV_ABORT:
- os->aborted = TRUE;
- os_reset_session(os);
- OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
- break;
- case OBEX_EV_REQDONE:
- switch (cmd) {
- case OBEX_CMD_CONNECT:
- break;
- case OBEX_CMD_DISCONNECT:
- OBEX_TransportDisconnect(obex);
- break;
- case OBEX_CMD_PUT:
- case OBEX_CMD_GET:
- case OBEX_CMD_SETPATH:
- default:
- os_reset_session(os);
- break;
- }
- break;
- case OBEX_EV_REQHINT:
- os->cmd = cmd;
- switch (cmd) {
- case OBEX_CMD_PUT:
- os->checked = FALSE;
- OBEX_ObjectReadStream(obex, obj, NULL);
- case OBEX_CMD_GET:
- case OBEX_CMD_SETPATH:
- case OBEX_CMD_CONNECT:
- case OBEX_CMD_DISCONNECT:
- case OBEX_CMD_ACTION:
- OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE,
- OBEX_RSP_SUCCESS);
- break;
- default:
- OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
- OBEX_RSP_NOT_IMPLEMENTED);
- break;
- }
- break;
- case OBEX_EV_REQCHECK:
- switch (cmd) {
- case OBEX_CMD_PUT:
- if (os->service)
- check_put(obex, obj);
- break;
- default:
- break;
- }
- break;
- case OBEX_EV_REQ:
- switch (cmd) {
- case OBEX_CMD_DISCONNECT:
- break;
- case OBEX_CMD_CONNECT:
- cmd_connect(os, obex, obj);
- break;
- case OBEX_CMD_SETPATH:
- cmd_setpath(os, obex, obj);
- break;
- case OBEX_CMD_GET:
- cmd_get(os, obex, obj);
- break;
- case OBEX_CMD_PUT:
- cmd_put(os, obex, obj);
- break;
- case OBEX_CMD_ACTION:
- cmd_action(os, obex, obj);
- break;
- default:
- DBG("Unknown request: 0x%X", cmd);
- OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
- OBEX_RSP_NOT_IMPLEMENTED);
- break;
- }
- break;
- case OBEX_EV_STREAMAVAIL:
- err = obex_read_stream(os, obex, obj);
- if (err == -EAGAIN) {
- OBEX_SuspendRequest(obex, obj);
- os->obj = obj;
- os->driver->set_io_watch(os->object, handle_async_io,
- os);
- } else if (err < 0)
- os_set_response(obj, err);
+ DBG("");
- break;
- case OBEX_EV_STREAMEMPTY:
- err = obex_write_stream(os, obex, obj);
- if (err == -EAGAIN) {
- OBEX_SuspendRequest(obex, obj);
- os->stream_suspended = TRUE;
- os->obj = obj;
- os->driver->set_io_watch(os->object, handle_async_io,
- os);
- } else if (err < 0)
- os_set_response(obj, err);
+ print_event(G_OBEX_OP_ABORT, -1);
- break;
- case OBEX_EV_LINKERR:
- break;
- case OBEX_EV_PARSEERR:
- break;
- case OBEX_EV_UNEXPECTED:
- break;
+ os_reset_session(os);
- default:
- DBG("Unknown evt %d", evt);
- break;
- }
+ os_set_response(os, 0);
}
-static void obex_handle_destroy(void *user_data)
+static void obex_session_destroy(struct obex_session *os)
{
- struct obex_session *os;
- obex_t *obex = user_data;
-
DBG("");
- os = OBEX_GetUserData(obex);
-
os_reset_session(os);
if (os->service && os->service->disconnect)
os->service->disconnect(os, os->service_data);
obex_session_free(os);
-
- OBEX_Cleanup(obex);
}
-static gboolean obex_handle_input(GIOChannel *io,
- GIOCondition cond, void *user_data)
+static void disconn_func(GObex *obex, GError *err, gpointer user_data)
{
- obex_t *obex = user_data;
-
- if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
- error("obex_handle_input: poll event %s%s%s",
- (cond & G_IO_HUP) ? "HUP " : "",
- (cond & G_IO_ERR) ? "ERR " : "",
- (cond & G_IO_NVAL) ? "NVAL " : "");
- return FALSE;
- }
-
- if (OBEX_HandleInput(obex, 1) < 0) {
- error("Handle input error");
- return FALSE;
- }
+ struct obex_session *os = user_data;
- return TRUE;
+ error("disconnected: %s\n", err ? err->message : "<no err>");
+ obex_session_destroy(os);
}
int obex_session_start(GIOChannel *io, uint16_t tx_mtu, uint16_t rx_mtu,
struct obex_server *server)
{
struct obex_session *os;
- obex_t *obex;
- int ret, fd;
+ GObex *obex;
+ static uint32_t id = 0;
+
+ DBG("");
os = g_new0(struct obex_session, 1);
+ os->id = ++id;
os->service = obex_service_driver_find(server->drivers, NULL,
0, NULL, 0);
os->server = server;
- os->rx_mtu = rx_mtu != 0 ? rx_mtu : DEFAULT_RX_MTU;
- os->tx_mtu = tx_mtu != 0 ? tx_mtu : DEFAULT_TX_MTU;
os->size = OBJECT_SIZE_DELETE;
- obex = OBEX_Init(OBEX_TRANS_FD, obex_event_cb, 0);
+ obex = g_obex_new(io, G_OBEX_TRANSPORT_STREAM, rx_mtu, tx_mtu);
if (!obex) {
obex_session_free(os);
return -EIO;
}
- OBEX_SetUserData(obex, os);
- os->obex = obex;
-
- OBEX_SetTransportMTU(obex, os->rx_mtu, os->tx_mtu);
-
- fd = g_io_channel_unix_get_fd(io);
-
- ret = FdOBEX_TransportSetup(obex, fd, fd, 0);
- if (ret < 0) {
- obex_session_free(os);
- OBEX_Cleanup(obex);
- return ret;
- }
+ g_obex_set_disconnect_function(obex, disconn_func, os);
+ g_obex_add_request_function(obex, G_OBEX_OP_CONNECT, cmd_connect, os);
+ g_obex_add_request_function(obex, G_OBEX_OP_DISCONNECT, cmd_disconnect,
+ os);
+ g_obex_add_request_function(obex, G_OBEX_OP_PUT, cmd_put, os);
+ g_obex_add_request_function(obex, G_OBEX_OP_GET, cmd_get, os);
+ g_obex_add_request_function(obex, G_OBEX_OP_SETPATH, cmd_setpath, os);
+ g_obex_add_request_function(obex, G_OBEX_OP_ACTION, cmd_action, os);
+ g_obex_add_request_function(obex, G_OBEX_OP_ABORT, cmd_abort, os);
- g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- obex_handle_input, obex, obex_handle_destroy);
+ os->obex = obex;
os->io = g_io_channel_ref(io);
sessions = g_slist_prepend(sessions, os);
diff --git a/src/server.c b/src/server.c
index f91a622..e5dc22d 100644
--- a/src/server.c
+++ b/src/server.c
@@ -33,10 +33,10 @@
#include <fcntl.h>
#include <errno.h>
#include <string.h>
+#include <inttypes.h>
#include <glib.h>
-
-#include <openobex/obex.h>
+#include <gobex.h>
#include "log.h"
#include "obex.h"
--
1.7.7.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH obexd 2/2] Remove dependency on OpenOBEX
2011-11-29 9:09 [PATCH obexd 1/2] Port core daemon to gobex Luiz Augusto von Dentz
@ 2011-11-29 9:09 ` Luiz Augusto von Dentz
2011-11-29 9:20 ` [PATCH obexd 1/2] Port core daemon to gobex Johan Hedberg
1 sibling, 0 replies; 3+ messages in thread
From: Luiz Augusto von Dentz @ 2011-11-29 9:09 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Now that the server also uses gobex there is no need to depend on
OpenOBEX anymore.
---
Makefile.am | 14 ++++++--------
configure.ac | 5 -----
2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 2582651..af03f2e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -85,9 +85,8 @@ src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) $(btio_sources) \
src/server.h src/server.c
src_obexd_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @GTHREAD_LIBS@ \
- @EBOOK_LIBS@ @OPENOBEX_LIBS@ \
- @BLUEZ_LIBS@ @LIBICAL_LIBS@ \
- @TRACKER_LIBS@ -ldl
+ @EBOOK_LIBS@ @BLUEZ_LIBS@ \
+ @LIBICAL_LIBS@ @TRACKER_LIBS@ -ldl
src_obexd_LDFLAGS = -Wl,--export-dynamic
@@ -129,11 +128,10 @@ endif
service_DATA = $(service_in_files:.service.in=.service)
-AM_CFLAGS = @OPENOBEX_CFLAGS@ @BLUEZ_CFLAGS@ @EBOOK_CFLAGS@ \
- @GTHREAD_CFLAGS@ @GLIB_CFLAGS@ @DBUS_CFLAGS@ \
- @LIBICAL_CFLAGS@ -D_FILE_OFFSET_BITS=64 \
- @TRACKER_CFLAGS@ \
- -DOBEX_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\"
+AM_CFLAGS = @BLUEZ_CFLAGS@ @EBOOK_CFLAGS@ @GTHREAD_CFLAGS@ @GLIB_CFLAGS@ \
+ @DBUS_CFLAGS@ @LIBICAL_CFLAGS@ @TRACKER_CFLAGS@ \
+ -DOBEX_PLUGIN_BUILTIN -DPLUGINDIR=\""$(plugindir)"\" \
+ -D_FILE_OFFSET_BITS=64
INCLUDES = -I$(builddir)/src -I$(srcdir)/src -I$(srcdir)/plugins \
-I$(srcdir)/gdbus \
diff --git a/configure.ac b/configure.ac
index 962e2e7..fca284e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -89,11 +89,6 @@ AC_CHECK_LIB(dbus-1, dbus_connection_can_send_type, dummy=yes,
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
-PKG_CHECK_MODULES(OPENOBEX, openobex, dummy=yes,
- AC_MSG_ERROR(libopenobex is required))
-AC_SUBST(OPENOBEX_CFLAGS)
-AC_SUBST(OPENOBEX_LIBS)
-
PKG_CHECK_MODULES(BLUEZ, bluez, dummy=yes,
AC_MSG_ERROR(libbluetooth is required))
AC_SUBST(BLUEZ_CFLAGS)
--
1.7.7.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH obexd 1/2] Port core daemon to gobex
2011-11-29 9:09 [PATCH obexd 1/2] Port core daemon to gobex Luiz Augusto von Dentz
2011-11-29 9:09 ` [PATCH obexd 2/2] Remove dependency on OpenOBEX Luiz Augusto von Dentz
@ 2011-11-29 9:20 ` Johan Hedberg
1 sibling, 0 replies; 3+ messages in thread
From: Johan Hedberg @ 2011-11-29 9:20 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
Hi Luiz,
On Tue, Nov 29, 2011, Luiz Augusto von Dentz wrote:
> ---
> src/manager.c | 26 +-
> src/obex-priv.h | 12 +-
> src/obex.c | 1395 ++++++++++++++++++++++---------------------------------
> src/server.c | 4 +-
> 4 files changed, 577 insertions(+), 860 deletions(-)
Both patches applied. Thanks.
Johan
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-11-29 9:20 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-29 9:09 [PATCH obexd 1/2] Port core daemon to gobex Luiz Augusto von Dentz
2011-11-29 9:09 ` [PATCH obexd 2/2] Remove dependency on OpenOBEX Luiz Augusto von Dentz
2011-11-29 9:20 ` [PATCH obexd 1/2] Port core daemon to gobex Johan Hedberg
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.