[Spice-devel] [PATCH vd_agent V2] drag-n-drop: Add drag-and-drop support for linux agent
Dunrong Huang
riegamaths at gmail.com
Fri Nov 23 03:17:45 PST 2012
The patch makes linux agent support drag-n-drop feature.
Signed-off-by: Dunrong Huang <riegamaths at gmail.com>
---
V1 -> V2:
* New transfer protocol
src/vdagent.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/vdagentd.c | 44 +++++++++++++++++
2 files changed, 197 insertions(+)
diff --git a/src/vdagent.c b/src/vdagent.c
index 0af82b1..23fa31c 100644
--- a/src/vdagent.c
+++ b/src/vdagent.c
@@ -33,6 +33,8 @@
#include <signal.h>
#include <sys/select.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
#include <spice/vd_agent.h>
#include "udscs.h"
@@ -40,6 +42,27 @@
#include "vdagentd-proto-strings.h"
#include "vdagent-x11.h"
+typedef struct AgentData {
+ int dnd_fd;
+ int file_size;
+ int read_bypes;
+} AgentData;
+
+typedef struct AgentFileXferTask {
+ uint32_t id;
+ int file_fd;
+ uint64_t read_bytes;
+ VDAgentFileXferStartMessage *start_msg;
+ struct AgentFileXferTask *next;
+} AgentFileXferTask;
+static AgentFileXferTask agent_file_xfer_task_list = {
+ -1,
+ -1,
+ 0,
+ NULL,
+ NULL
+};
+
static const char *portdev = "/dev/virtio-ports/com.redhat.spice.0";
static int debug = 0;
static struct vdagent_x11 *x11 = NULL;
@@ -47,6 +70,124 @@ static struct udscs_connection *client = NULL;
static int quit = 0;
static int version_mismatch = 0;
+/* Remove task from task list */
+static void file_xfer_task_remove(uint32_t id)
+{
+ AgentFileXferTask *list, *prev;
+
+ prev = &agent_file_xfer_task_list;
+ list = agent_file_xfer_task_list.next;
+
+ while (list) {
+ if (list->id == id) {
+ prev->next = list->next;
+ break;
+ }
+ prev = list;
+ list = list->next;
+ }
+}
+
+static const char *get_home_dir()
+{
+ static const char *home = NULL;
+ struct passwd *p;
+
+ if (home)
+ return home;
+
+ home = getenv ("HOME");
+ if (!home) {
+ p = getpwuid(getuid());
+ home = p->pw_dir;
+ }
+
+ return home ? home : "";
+}
+
+static void vdagent_file_xfer_start(VDAgentFileXferStartMessage *msg)
+{
+ AgentFileXferTask *new, *list;
+ char file_path[1024]; /* file path, limit to 1024 chars */
+
+ list = &agent_file_xfer_task_list;
+
+ new = malloc(sizeof(*new));
+ memset(new, 0, sizeof(*new));
+ new->id = msg->id;
+ new->start_msg = malloc(sizeof(VDAgentFileXferStartMessage));
+ memcpy(new->start_msg, msg, sizeof(VDAgentFileXferStartMessage));
+
+ /* TODO: use file mode passed by client */
+ snprintf(file_path, sizeof(file_path), "%s/Desktop/%s",
+ get_home_dir(), (char *)msg->file_name);
+ new->file_fd = open(file_path, O_CREAT | O_WRONLY, 0644);
+ if (new->file_fd == -1) {
+ syslog(LOG_ERR, "Create file error:%s\n", strerror(errno));
+ goto error;
+ }
+
+ if (ftruncate(new->file_fd, msg->file_size) < 0) {
+ close(new->file_fd);
+ goto error;
+ }
+
+ while (list->next) {
+ list = list->next;
+ }
+ list->next = new;
+
+ udscs_write(client, VDAGENTD_FILE_XFER_STATUS,
+ msg->id, VD_AGENT_FILE_XFER_RESULT_SUCCESS, NULL, 0);
+ return ;
+
+error:
+ udscs_write(client, VDAGENTD_FILE_XFER_STATUS,
+ msg->id, VD_AGENT_FILE_XFER_RESULT_ERROR, NULL, 0);
+ free(new->start_msg);
+ free(new);
+}
+
+static void vdagent_file_xfer_status(VDAgentFileXferStatusMessage *msg)
+{
+
+}
+
+static void vdagent_file_xfer_data(VDAgentFileXferDataMessage *msg)
+{
+ AgentFileXferTask *task = NULL, *list;
+ int len;
+
+ list = &agent_file_xfer_task_list;
+ while (list) {
+ if (list->id == msg->id) {
+ task = list;
+ break;
+ }
+ list = list->next;
+ }
+ if (task == NULL) {
+ syslog(LOG_INFO, "Can not find task:%d", msg->id);
+ return ;
+ }
+
+ len = pwrite(task->file_fd, msg->data, msg->size, task->read_bytes);
+ if (len == -1) {
+ syslog(LOG_ERR, "write file error:%s\n", strerror(errno));
+ /* TODO: close, cancel dnd */
+ return ;
+ }
+
+ task->read_bytes += msg->size;
+ if (task->read_bytes >= task->start_msg->file_size) {
+ syslog(LOG_DEBUG, "task %d have been finished", task->id);
+ file_xfer_task_remove(task->id);
+ close(task->file_fd);
+ free(task->start_msg);
+ free(task);
+ }
+}
+
void daemon_read_complete(struct udscs_connection **connp,
struct udscs_message_header *header, uint8_t *data)
{
@@ -82,6 +223,18 @@ void daemon_read_complete(struct udscs_connection **connp,
version_mismatch = 1;
}
break;
+ case VDAGENTD_FILE_XFER_START:
+ vdagent_file_xfer_start((VDAgentFileXferStartMessage *)data);
+ free(data);
+ break;
+ case VDAGENTD_FILE_XFER_STATUS:
+ vdagent_file_xfer_status((VDAgentFileXferStatusMessage *)data);
+ free(data);
+ break;
+ case VDAGENTD_FILE_XFER_DATA:
+ vdagent_file_xfer_data((VDAgentFileXferDataMessage *)data);
+ free(data);
+ break;
default:
syslog(LOG_ERR, "Unknown message from vdagentd type: %d, ignoring",
header->type);
diff --git a/src/vdagentd.c b/src/vdagentd.c
index a4db935..7cda887 100644
--- a/src/vdagentd.c
+++ b/src/vdagentd.c
@@ -214,6 +214,35 @@ static void do_client_clipboard(struct vdagent_virtio_port *vport,
data, size);
}
+static void do_client_file_xfer(struct vdagent_virtio_port *vport,
+ int port_nr,
+ VDAgentMessage *message_header,
+ uint8_t *data)
+{
+ uint32_t msg_type;
+
+ if (!active_session_conn) {
+ syslog(LOG_WARNING,
+ "Could not find an agent connnection belonging to the "
+ "active session, ignoring client clipboard request");
+ return;
+ }
+
+ switch (message_header->type) {
+ case VD_AGENT_FILE_XFER_START:
+ msg_type = VDAGENTD_FILE_XFER_START;
+ break;
+ case VD_AGENT_FILE_XFER_STATUS:
+ msg_type = VDAGENTD_FILE_XFER_STATUS;
+ break;
+ case VD_AGENT_FILE_XFER_DATA:
+ msg_type = VDAGENTD_FILE_XFER_DATA;
+ break;
+ }
+
+ udscs_write(active_session_conn, msg_type, 0, 0, data, message_header->size);
+}
+
int virtio_port_read_complete(
struct vdagent_virtio_port *vport,
int port_nr,
@@ -283,6 +312,11 @@ int virtio_port_read_complete(
}
do_client_clipboard(vport, message_header, data);
break;
+ case VD_AGENT_FILE_XFER_START:
+ case VD_AGENT_FILE_XFER_STATUS:
+ case VD_AGENT_FILE_XFER_DATA:
+ do_client_file_xfer(vport, port_nr, message_header, data);
+ break;
default:
syslog(LOG_WARNING, "unknown message type %d, ignoring",
message_header->type);
@@ -614,6 +648,16 @@ void agent_read_complete(struct udscs_connection **connp,
return;
}
break;
+ case VDAGENTD_FILE_XFER_STATUS:{
+ VDAgentFileXferStatusMessage status;
+ status.id = header->arg1;
+ status.result = header->arg2;
+ vdagent_virtio_port_write(virtio_port, VDP_CLIENT_PORT,
+ VD_AGENT_FILE_XFER_STATUS, 0,
+ (uint8_t *)&status, sizeof(status));
+ break;
+ }
+
default:
syslog(LOG_ERR, "unknown message from vdagent: %u, ignoring",
header->type);
--
1.8.0
More information about the Spice-devel
mailing list