diff --git a/obexd/src/mimetype.c b/obexd/src/mimetype.c
index f773254..80f7374 100644
--- a/obexd/src/mimetype.c
+++ b/obexd/src/mimetype.c
static GSList *drivers = NULL;
+static GSList *watches = NULL;
+
+struct io_watch {
+ gpointer object;
+ obex_object_io_func func;
+ gpointer user_data;
+};
+
+void obex_object_set_io_flags(gpointer object, int flags)
+{
+ GSList *l;
+
+ for (l = watches; l; l = l->next) {
+ struct io_watch *watch = l->data;
+
+ if (watch->object != object)
+ continue;
+
+ if (watch->func(object, flags, watch->user_data) == TRUE)
+ continue;
+
+ if (g_slist_find(watches, watch) == NULL)
+ continue;
+
+ watches = g_slist_remove(watches, watch);
+ g_free(watch);
+ }
+}
+
+static struct io_watch *find_io_watch(gpointer object)
+{
+ GSList *l;
+
+ for (l = watches; l; l = l->next) {
+ struct io_watch *watch = l->data;
+
+ if (watch->object == object)
+ return watch;
+ }
+
+ return NULL;
+}
+
+static void reset_io_watch(gpointer object)
+{
+ struct io_watch *watch;
+
+ watch = find_io_watch(object);
+ if (watch == NULL)
+ return;
+
+ watches = g_slist_remove(watches, watch);
+ g_free(watch);
+}
+
+static int set_io_watch(gpointer object, obex_object_io_func func,
+ gpointer user_data)
+{
+ struct io_watch *watch;
+
+ if (func == NULL) {
+ reset_io_watch(object);
+ return 0;
+ }
+
+ watch = find_io_watch(object);
+ if (watch)
+ return -EPERM;
+
+ watch = g_new0(struct io_watch, 1);
+ watch->object = object;
+ watch->func = func;
+ watch->user_data = user_data;
+
+ watches = g_slist_append(watches, watch);
+
+ return 0;
+}
+
struct obex_mime_type_driver *obex_mime_type_driver_find(const guint8 *target, const char *mimetype)
{
GSList *l;
return -EPERM;
}
+ if (driver->set_io_watch == NULL)
+ driver->set_io_watch = set_io_watch;
+
debug("driver %p mimetype %s registered", driver, driver->mimetype);
drivers = g_slist_append(drivers, driver);
diff --git a/obexd/src/mimetype.h b/obexd/src/mimetype.h
index 452ebb8..8ddb9e3 100644
--- a/obexd/src/mimetype.h
+++ b/obexd/src/mimetype.h
#define TARGET_SIZE 16
+typedef gboolean (*obex_object_io_func) (gpointer object, int flags,
+ gpointer user_data);
+
struct obex_mime_type_driver {
const guint8 *target;
const char *mimetype;
ssize_t (*read) (gpointer object, void *buf, size_t count);
ssize_t (*write) (gpointer object, const void *buf, size_t count);
int (*remove) (const char *name);
+ int (*set_io_watch) (gpointer object, obex_object_io_func func,
+ gpointer user_data);
};
int obex_mime_type_driver_register(struct obex_mime_type_driver *driver);
void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver);
struct obex_mime_type_driver *obex_mime_type_driver_find(const guint8 *target,
const char *mimetype);
+
+void obex_object_set_io_flags(gpointer object, int flags);
diff --git a/obexd/src/obex.c b/obexd/src/obex.c
index 68638d3..a596171 100644
--- a/obexd/src/obex.c
+++ b/obexd/src/obex.c
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);
os->object = NULL;
+ os->obj = NULL;
if (os->aborted && os->cmd == OBEX_CMD_PUT && os->current_folder) {
gchar *path;
path = g_build_filename(os->current_folder, os->name, NULL);
g_free(os->buf);
os->buf = NULL;
}
+
os->driver = NULL;
os->aborted = FALSE;
os->offset = 0;
len = os->driver->read(os->object, os->buf, os->tx_mtu);
if (len < 0) {
gint err = errno;
+
error("read(): %s (%d)", strerror(err), err);
+ if (err == EAGAIN)
+ return -err;
+
g_free(os->buf);
os->buf = NULL;
return -err;
return 0;
}
+static gboolean handle_async_io(gpointer object, int flags, gpointer user_data)
+{
+ struct obex_session *os = user_data;
+ int ret = 0;
+
+ if (flags & (G_IO_ERR | G_IO_HUP)) {
+ ret = -errno;
+ goto proceed;
+ }
+
+ if (flags & (G_IO_IN | G_IO_PRI))
+ ret = obex_write_stream(os, os->obex, os->obj);
+ else if (flags & G_IO_OUT)
+ ret = obex_read_stream(os, os->obex, os->obj);
+
+proceed:
+ switch (ret) {
+ case -EINVAL:
+ OBEX_ObjectSetRsp(os->obj, OBEX_RSP_BAD_REQUEST,
+ OBEX_RSP_BAD_REQUEST);
+ case -EPERM:
+ OBEX_ObjectSetRsp(os->obj, OBEX_RSP_FORBIDDEN,
+ OBEX_RSP_FORBIDDEN);
+ break;
+ default:
+ if (ret < 0)
+ OBEX_ObjectSetRsp(os->obj,
+ OBEX_RSP_INTERNAL_SERVER_ERROR,
+ OBEX_RSP_INTERNAL_SERVER_ERROR);
+ break;
+ }
+
+ OBEX_ResumeRequest(os->obex);
+
+ return FALSE;
+}
+
static gboolean check_put(obex_t *obex, obex_object_t *obj)
{
struct obex_session *os;
case -EPERM:
OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
return FALSE;
+ case -EAGAIN:
+ OBEX_SuspendRequest(obex, obj);
+ os->obj = obj;
+ os->driver->set_io_watch(os->object, handle_async_io, os);
+ return TRUE;
default:
debug("Unhandled chkput error: %d", ret);
OBEX_ObjectSetRsp(obj, OBEX_RSP_INTERNAL_SERVER_ERROR,
case OBEX_CMD_PUT:
case OBEX_CMD_GET:
case OBEX_CMD_SETPATH:
+ default:
os_session_mark_aborted(os);
if (os->service->reset)
os->service->reset(obex);
os_reset_session(os);
break;
- default:
- break;
}
break;
case OBEX_EV_REQHINT:
OBEX_ObjectSetRsp(obj,
OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
break;
+ case -EAGAIN:
+ OBEX_SuspendRequest(obex, obj);
+ os->obj = obj;
+ os->driver->set_io_watch(os->object, handle_async_io, os);
+ break;
default:
OBEX_ObjectSetRsp(obj,
OBEX_RSP_INTERNAL_SERVER_ERROR,
break;
case OBEX_EV_STREAMEMPTY:
- obex_write_stream(os, obex, obj);
+ switch (obex_write_stream(os, obex, obj)) {
+ case -EPERM:
+ OBEX_ObjectSetRsp(obj,
+ OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
+ break;
+ case -EAGAIN:
+ OBEX_SuspendRequest(obex, obj);
+ os->obj = obj;
+ os->driver->set_io_watch(os->object, handle_async_io,
+ os);
+ break;
+ default:
+ break;
+ }
+
break;
case OBEX_EV_LINKERR:
break;
diff --git a/obexd/src/obex.h b/obexd/src/obex.h
index 3c3106c..3e206ad 100644
--- a/obexd/src/obex.h
+++ b/obexd/src/obex.h
struct server *server;
gboolean checked;
obex_t *obex;
+ obex_object_t *obj;
struct obex_mime_type_driver *driver;
gboolean finished;
};