From c672335e313bb556583db6facc09f0300ec37f6b Mon Sep 17 00:00:00 2001 From: Luiz Augusto Von Dentz Date: Thu, 25 Feb 2010 16:22:55 +0200 Subject: [PATCH] obexd: Add set_io_watch to mimetype drivers This should enable async drivers where read/write may block to return EAGAIN which makes the core to wait until the data is available. --- obexd/src/mimetype.c | 82 ++++++++++++++++++++++++++++++++++++++++++++ obexd/src/mimetype.h | 7 ++++ obexd/src/obex.c | 73 +++++++++++++++++++++++++++++++++++++-- obexd/src/obex.h | 1 + 4 files changed, 160 insertions(+), 3 deletions(-) diff --git a/obexd/src/mimetype.c b/obexd/src/mimetype.c index f773254c4..80f73742b 100644 --- a/obexd/src/mimetype.c +++ b/obexd/src/mimetype.c @@ -38,6 +38,85 @@ 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; @@ -68,6 +147,9 @@ int obex_mime_type_driver_register(struct obex_mime_type_driver *driver) 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 452ebb8f0..8ddb9e3bc 100644 --- a/obexd/src/mimetype.h +++ b/obexd/src/mimetype.h @@ -23,6 +23,9 @@ #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; @@ -31,9 +34,13 @@ struct obex_mime_type_driver { 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 68638d323..a596171ff 100644 --- a/obexd/src/obex.c +++ b/obexd/src/obex.c @@ -67,8 +67,10 @@ typedef struct { 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); @@ -89,6 +91,7 @@ static void os_reset_session(struct obex_session *os) g_free(os->buf); os->buf = NULL; } + os->driver = NULL; os->aborted = FALSE; os->offset = 0; @@ -432,7 +435,11 @@ static gint obex_write_stream(struct obex_session *os, 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; @@ -558,6 +565,43 @@ static gint obex_read_stream(struct obex_session *os, obex_t *obex, 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; @@ -658,6 +702,11 @@ static gboolean check_put(obex_t *obex, obex_object_t *obj) 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, @@ -726,13 +775,12 @@ static void obex_event(obex_t *obex, obex_object_t *obj, gint mode, 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: @@ -795,6 +843,11 @@ static void obex_event(obex_t *obex, obex_object_t *obj, gint mode, 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, @@ -804,7 +857,21 @@ static void obex_event(obex_t *obex, obex_object_t *obj, gint mode, 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 3c3106cae..3e206ad07 100644 --- a/obexd/src/obex.h +++ b/obexd/src/obex.h @@ -77,6 +77,7 @@ struct obex_session { struct server *server; gboolean checked; obex_t *obex; + obex_object_t *obj; struct obex_mime_type_driver *driver; gboolean finished; }; -- 2.47.3