diff options
Diffstat (limited to 'src/vdagent.c')
-rw-r--r-- | src/vdagent.c | 175 |
1 files changed, 11 insertions, 164 deletions
diff --git a/src/vdagent.c b/src/vdagent.c index 78c7910..0250ec8 100644 --- a/src/vdagent.c +++ b/src/vdagent.c @@ -34,178 +34,21 @@ #include <sys/select.h> #include <sys/stat.h> #include <spice/vd_agent.h> -#include <glib.h> #include "udscs.h" #include "vdagentd-proto.h" #include "vdagentd-proto-strings.h" #include "vdagent-x11.h" - -typedef struct AgentFileXferTask { - uint32_t id; - int file_fd; - uint64_t read_bytes; - char *file_name; - uint64_t file_size; -} AgentFileXferTask; - -GHashTable *agent_file_xfer_tasks = NULL; +#include "vdagent-file-xfers.h" static const char *portdev = "/dev/virtio-ports/com.redhat.spice.0"; static int debug = 0; static struct vdagent_x11 *x11 = NULL; +static struct vdagent_file_xfers *vdagent_file_xfers = NULL; static struct udscs_connection *client = NULL; static int quit = 0; static int version_mismatch = 0; -static void agent_file_xfer_task_free(gpointer data) -{ - AgentFileXferTask *task = data; - - g_return_if_fail(task != NULL); - - if (task->file_fd > 0) { - close(task->file_fd); - } - g_free(task->file_name); - g_free(task); -} - -/* Parse start messag then create a new file xfer task */ -static AgentFileXferTask *vdagent_parse_start_msg( - VDAgentFileXferStartMessage *msg) -{ - GKeyFile *keyfile = NULL; - AgentFileXferTask *task = NULL; - GError *error = NULL; - - keyfile = g_key_file_new(); - if (g_key_file_load_from_data(keyfile, - (const gchar *)msg->data, - -1, - G_KEY_FILE_NONE, &error) == FALSE) { - syslog(LOG_ERR, "failed to load keyfile from data, error:%s\n", - error->message); - goto error; - } - task = g_new0(AgentFileXferTask, 1); - task->id = msg->id; - task->file_name = g_key_file_get_string( - keyfile, "vdagent-file-xfer", "name", &error); - if (error) { - syslog(LOG_ERR, "failed to parse filename, error:%s\n", error->message); - goto error; - } - task->file_size = g_key_file_get_uint64( - keyfile, "vdagent-file-xfer", "size", &error); - if (error) { - syslog(LOG_ERR, "failed to parse filesize, error:%s\n", error->message); - goto error; - } - - g_key_file_free(keyfile); - return task; - -error: - g_clear_error(&error); - agent_file_xfer_task_free(task); - if (keyfile) { - g_key_file_free(keyfile); - } - return NULL; -} - -static void vdagent_file_xfer_start(VDAgentFileXferStartMessage *msg) -{ - AgentFileXferTask *new; - char *file_path; - const gchar *desktop; - - new = vdagent_parse_start_msg(msg); - if (new == NULL) { - goto error; - } - - desktop = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP); - if (desktop == NULL) { - goto error; - } - file_path = g_build_filename(desktop, new->file_name, NULL); - new->file_fd = open(file_path, O_CREAT | O_WRONLY, 0644); - g_free(file_path); - if (new->file_fd == -1) { - syslog(LOG_ERR, "Create file error:%s\n", strerror(errno)); - goto error; - } - - if (ftruncate(new->file_fd, new->file_size) < 0) { - goto error; - } - - g_hash_table_insert(agent_file_xfer_tasks, GINT_TO_POINTER(msg->id), new); - - udscs_write(client, VDAGENTD_FILE_XFER_STATUS, - msg->id, VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA, NULL, 0); - return ; - -error: - udscs_write(client, VDAGENTD_FILE_XFER_STATUS, - msg->id, VD_AGENT_FILE_XFER_STATUS_ERROR, NULL, 0); - agent_file_xfer_task_free(new); -} - -static void vdagent_file_xfer_status(VDAgentFileXferStatusMessage *msg) -{ - syslog(LOG_INFO, "task %d received response %d", msg->id, msg->result); - - if (msg->result == VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA) { - /* Do nothing */ - } else { - /* Error, remove this task */ - gboolean found; - found = g_hash_table_remove(agent_file_xfer_tasks, GINT_TO_POINTER(msg->id)); - if (found) { - syslog(LOG_DEBUG, "remove task %d", msg->id); - } else { - syslog(LOG_ERR, "can not find task %d", msg->id); - } - } -} - -static void vdagent_file_xfer_data(VDAgentFileXferDataMessage *msg) -{ - AgentFileXferTask *task; - int len; - - task = g_hash_table_lookup(agent_file_xfer_tasks, GINT_TO_POINTER(msg->id)); - if (task == NULL) { - syslog(LOG_INFO, "Can not find task:%d", msg->id); - return ; - } - - len = write(task->file_fd, msg->data, msg->size); - 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->file_size) { - gboolean found; - if (task->read_bytes > task->file_size) { - syslog(LOG_ERR, "error: received too much data"); - } - syslog(LOG_DEBUG, "task %d have been finished", task->id); - found = g_hash_table_remove(agent_file_xfer_tasks, GINT_TO_POINTER(msg->id)); - if (found) { - syslog(LOG_DEBUG, "remove task %d", msg->id); - } else { - syslog(LOG_ERR, "can not find task %d", msg->id); - } - } -} - void daemon_read_complete(struct udscs_connection **connp, struct udscs_message_header *header, uint8_t *data) { @@ -242,15 +85,18 @@ void daemon_read_complete(struct udscs_connection **connp, } break; case VDAGENTD_FILE_XFER_START: - vdagent_file_xfer_start((VDAgentFileXferStartMessage *)data); + vdagent_file_xfers_start(vdagent_file_xfers, + (VDAgentFileXferStartMessage *)data); free(data); break; case VDAGENTD_FILE_XFER_STATUS: - vdagent_file_xfer_status((VDAgentFileXferStatusMessage *)data); + vdagent_file_xfers_status(vdagent_file_xfers, + (VDAgentFileXferStatusMessage *)data); free(data); break; case VDAGENTD_FILE_XFER_DATA: - vdagent_file_xfer_data((VDAgentFileXferDataMessage *)data); + vdagent_file_xfers_data(vdagent_file_xfers, + (VDAgentFileXferDataMessage *)data); free(data); break; default: @@ -370,8 +216,6 @@ int main(int argc, char *argv[]) if (do_daemonize) daemonize(); - agent_file_xfer_tasks = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, agent_file_xfer_task_free); - reconnect: if (version_mismatch) { syslog(LOG_INFO, "Version mismatch, restarting"); @@ -389,6 +233,8 @@ reconnect: return 1; } + vdagent_file_xfers = vdagent_file_xfers_create(client); + while (client && !quit) { FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -412,6 +258,7 @@ reconnect: udscs_client_handle_fds(&client, &readfds, &writefds); } + vdagent_file_xfers_destroy(vdagent_file_xfers); vdagent_x11_destroy(x11, client == NULL); udscs_destroy_connection(&client); if (!quit) |