summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-02-22 15:41:24 +0100
committerHans de Goede <hdegoede@redhat.com>2013-02-22 17:54:23 +0100
commit79c2e93136ec8ce5ee95c8366923b8f47a38e224 (patch)
tree8e68a53002bb2da839e9633d06d6d8def613b0c5
parent60603deb4dd4b643adbc038ed8d83ceab4dadc14 (diff)
downloadvd_agent-79c2e93136ec8ce5ee95c8366923b8f47a38e224.tar.gz
vd_agent-79c2e93136ec8ce5ee95c8366923b8f47a38e224.tar.xz
vd_agent-79c2e93136ec8ce5ee95c8366923b8f47a38e224.zip
file-xfers: Move file xfer code to its own file
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--Makefile.am2
-rw-r--r--src/vdagent-file-xfers.c221
-rw-r--r--src/vdagent-file-xfers.h40
-rw-r--r--src/vdagent.c175
4 files changed, 273 insertions, 165 deletions
diff --git a/Makefile.am b/Makefile.am
index 3aed69a..d218183 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,7 @@ sbin_PROGRAMS = src/spice-vdagentd
src_spice_vdagent_CFLAGS = $(X_CFLAGS) $(SPICE_CFLAGS) $(GLIB2_CFLAGS)
src_spice_vdagent_LDADD = $(X_LIBS) $(SPICE_LIBS) $(GLIB2_LIBS)
-src_spice_vdagent_SOURCES = src/vdagent.c src/vdagent-x11.c src/vdagent-x11-randr.c src/udscs.c
+src_spice_vdagent_SOURCES = src/vdagent.c src/vdagent-x11.c src/vdagent-x11-randr.c src/vdagent-file-xfers.c src/udscs.c
src_spice_vdagentd_CFLAGS = $(DBUS_CFLAGS) $(LIBSYSTEMD_LOGIN_CFLAGS) $(PCIACCESS_CFLAGS) $(SPICE_CFLAGS)
src_spice_vdagentd_LDADD = $(DBUS_LIBS) $(LIBSYSTEMD_LOGIN_LIBS) $(PCIACCESS_LIBS) $(SPICE_LIBS)
diff --git a/src/vdagent-file-xfers.c b/src/vdagent-file-xfers.c
new file mode 100644
index 0000000..8c98d67
--- /dev/null
+++ b/src/vdagent-file-xfers.c
@@ -0,0 +1,221 @@
+/* vdagent file xfers code
+
+ Copyright 2013 Red Hat, Inc.
+
+ Red Hat Authors:
+ Hans de Goede <hdegoede@redhat.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <spice/vd_agent.h>
+#include <glib.h>
+
+#include "vdagentd-proto.h"
+#include "vdagent-file-xfers.h"
+
+struct vdagent_file_xfers {
+ GHashTable *xfers;
+ struct udscs_connection *vdagentd;
+};
+
+typedef struct AgentFileXferTask {
+ uint32_t id;
+ int file_fd;
+ uint64_t read_bytes;
+ char *file_name;
+ uint64_t file_size;
+} AgentFileXferTask;
+
+static void vdagent_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);
+}
+
+struct vdagent_file_xfers *vdagent_file_xfers_create(
+ struct udscs_connection *vdagentd)
+{
+ struct vdagent_file_xfers *xfers;
+
+ xfers = g_malloc(sizeof(*xfers));
+ xfers->xfers = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, vdagent_file_xfer_task_free);
+ xfers->vdagentd = vdagentd;
+
+ return xfers;
+}
+
+void vdagent_file_xfers_destroy(struct vdagent_file_xfers *xfers)
+{
+ g_hash_table_destroy(xfers->xfers);
+ g_free(xfers);
+}
+
+/* Parse start message 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);
+ vdagent_file_xfer_task_free(task);
+ if (keyfile) {
+ g_key_file_free(keyfile);
+ }
+ return NULL;
+}
+
+void vdagent_file_xfers_start(struct vdagent_file_xfers *xfers,
+ 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(xfers->xfers, GINT_TO_POINTER(msg->id), new);
+
+ udscs_write(xfers->vdagentd, VDAGENTD_FILE_XFER_STATUS,
+ msg->id, VD_AGENT_FILE_XFER_STATUS_CAN_SEND_DATA, NULL, 0);
+ return ;
+
+error:
+ udscs_write(xfers->vdagentd, VDAGENTD_FILE_XFER_STATUS,
+ msg->id, VD_AGENT_FILE_XFER_STATUS_ERROR, NULL, 0);
+ vdagent_file_xfer_task_free(new);
+}
+
+void vdagent_file_xfers_status(struct vdagent_file_xfers *xfers,
+ 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(xfers->xfers, 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 vdagent_file_xfers_data(struct vdagent_file_xfers *xfers,
+ VDAgentFileXferDataMessage *msg)
+{
+ AgentFileXferTask *task;
+ int len;
+
+ task = g_hash_table_lookup(xfers->xfers, 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(xfers->xfers, 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);
+ }
+ }
+}
diff --git a/src/vdagent-file-xfers.h b/src/vdagent-file-xfers.h
new file mode 100644
index 0000000..e51a18e
--- /dev/null
+++ b/src/vdagent-file-xfers.h
@@ -0,0 +1,40 @@
+/* vdagent file xfers header
+
+ Copyright 2013 Red Hat, Inc.
+
+ Red Hat Authors:
+ Hans de Goede <hdegoede@redhat.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __VDAGENT_FILE_XFERS_H
+#define __VDAGENT_FILE_XFERS_H
+
+#include "udscs.h"
+
+struct vdagent_file_xfers;
+
+struct vdagent_file_xfers *vdagent_file_xfers_create(
+ struct udscs_connection *vdagentd);
+void vdagent_file_xfers_destroy(struct vdagent_file_xfers *xfer);
+
+void vdagent_file_xfers_start(struct vdagent_file_xfers *xfers,
+ VDAgentFileXferStartMessage *msg);
+void vdagent_file_xfers_status(struct vdagent_file_xfers *xfers,
+ VDAgentFileXferStatusMessage *msg);
+void vdagent_file_xfers_data(struct vdagent_file_xfers *xfers,
+ VDAgentFileXferDataMessage *msg);
+
+#endif
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)