Diff between ab847c9cc106c6fa9250ce8aca51e90acce5e137 and c672335e313bb556583db6facc09f0300ec37f6b

Changed Files

File Additions Deletions Status
obexd/src/mimetype.c +82 -0 modified
obexd/src/mimetype.h +7 -0 modified
obexd/src/obex.c +70 -3 modified
obexd/src/obex.h +1 -0 modified

Full Patch

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
@@ -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 452ebb8..8ddb9e3 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 68638d3..a596171 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 3c3106c..3e206ad 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;
 };