From d30ade6befe8e1139e389d1b4208a2461a59ca71 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 12 Nov 2013 11:46:32 -0800 Subject: [PATCH] Implement file download. --- src/protocols/rdp/client.c | 1 + src/protocols/rdp/client.h | 17 ++++++ src/protocols/rdp/guac_handlers.c | 57 +++++++++++++++++++ src/protocols/rdp/guac_handlers.h | 3 + .../rdp/guac_rdpdr/rdpdr_fs_messages.c | 52 +++++++++++------ 5 files changed, 114 insertions(+), 16 deletions(-) diff --git a/src/protocols/rdp/client.c b/src/protocols/rdp/client.c index e8a0ef0f..654f242c 100644 --- a/src/protocols/rdp/client.c +++ b/src/protocols/rdp/client.c @@ -308,6 +308,7 @@ BOOL rdp_freerdp_post_connect(freerdp* instance) { client->file_handler = rdp_guac_client_file_handler; client->blob_handler = rdp_guac_client_blob_handler; client->end_handler = rdp_guac_client_end_handler; + client->ack_handler = rdp_guac_client_ack_handler; return TRUE; diff --git a/src/protocols/rdp/client.h b/src/protocols/rdp/client.h index d28da7a1..28e6ebbd 100644 --- a/src/protocols/rdp/client.h +++ b/src/protocols/rdp/client.h @@ -207,6 +207,23 @@ typedef struct rdp_freerdp_context { } rdp_freerdp_context; +/** + * The transfer status of a file being downloaded. + */ +typedef struct guac_rdp_download_status { + + /** + * The file ID of the file being downloaded. + */ + int file_id; + + /** + * The current position within the file. + */ + uint64_t offset; + +} guac_rdp_download_status; + /** * Given the coordinates and dimensions of a rectangle, clips the rectangle to be * within the clipping bounds of the client data, if clipping is active. diff --git a/src/protocols/rdp/guac_handlers.c b/src/protocols/rdp/guac_handlers.c index 09baabbe..57f2ad55 100644 --- a/src/protocols/rdp/guac_handlers.c +++ b/src/protocols/rdp/guac_handlers.c @@ -639,3 +639,60 @@ int rdp_guac_client_end_handler(guac_client* client, guac_stream* stream) { return 0; } +int rdp_guac_client_ack_handler(guac_client* client, guac_stream* stream, + char* message, guac_protocol_status status) { + + /* Get status */ + guac_rdp_download_status* download = + (guac_rdp_download_status*) stream->data; + + /* Get filesystem, return error if no filesystem */ + guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem; + if (fs == NULL) { + guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)", + GUAC_PROTOCOL_STATUS_INTERNAL_ERROR); + guac_socket_flush(client->socket); + return 0; + } + + /* If successful, read data */ + if (status == GUAC_PROTOCOL_STATUS_SUCCESS) { + + /* Attempt read into buffer */ + char buffer[4096]; + int bytes_read = guac_rdp_fs_read(fs, download->file_id, + download->offset, buffer, sizeof(buffer)); + + /* If bytes read, send as blob */ + if (bytes_read > 0) { + download->offset += bytes_read; + guac_protocol_send_blob(client->socket, stream, + buffer, bytes_read); + } + + /* If EOF, send end */ + else if (bytes_read == 0) { + guac_protocol_send_end(client->socket, stream); + guac_client_free_stream(client, stream); + } + + /* Otherwise, fail stream */ + else { + guac_client_log_error(client, "Error reading file for download"); + guac_protocol_send_end(client->socket, stream); + guac_client_free_stream(client, stream); + } + + guac_socket_flush(client->socket); + + } + + /* Otherwise, return stream to client */ + else + guac_client_free_stream(client, stream); + + return 0; + + +} + diff --git a/src/protocols/rdp/guac_handlers.h b/src/protocols/rdp/guac_handlers.h index d37c7f23..3f2c6a67 100644 --- a/src/protocols/rdp/guac_handlers.h +++ b/src/protocols/rdp/guac_handlers.h @@ -73,5 +73,8 @@ int rdp_guac_client_blob_handler(guac_client* client, guac_stream* stream, int rdp_guac_client_end_handler(guac_client* client, guac_stream* stream); +int rdp_guac_client_ack_handler(guac_client* client, guac_stream* stream, + char* message, guac_protocol_status status); + #endif diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c index e7a64e4d..ffd33604 100644 --- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c +++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c @@ -226,30 +226,50 @@ void guac_rdpdr_fs_process_close(guac_rdpdr_device* device, int i; char c; - /* Get client */ + /* Get client and stream */ guac_client* client = device->rdpdr->client; - /* Allocate stream */ - guac_stream* stream = guac_client_alloc_stream(client); + int file_id = guac_rdp_fs_open((guac_rdp_fs*) device->data, + file->absolute_path, ACCESS_FILE_READ_DATA, 0, + DISP_FILE_OPEN, 0); - /* Get basename from absolute path */ - char* basename = file->absolute_path; - do { + /* If file opened successfully, start stream */ + if (file_id >= 0) { - c = file->absolute_path[i]; - if (c == '/' || c == '\\') - basename = &(file->absolute_path[i+1]); + guac_rdp_download_status* status; - i++; + /* Associate stream with transfer status */ + guac_stream* stream = guac_client_alloc_stream(client); + stream->data = status = malloc(sizeof(guac_rdp_download_status)); + status->file_id = file_id; + status->offset = 0; - } while (c != '\0'); + /* Get basename from absolute path */ + char* basename = file->absolute_path; + do { - GUAC_RDP_DEBUG(2, "Initiating download of \"%s\"", file->absolute_path); - guac_protocol_send_file(client->socket, stream, - "application/octet-stream", basename); - guac_socket_flush(client->socket); + c = file->absolute_path[i]; + if (c == '/' || c == '\\') + basename = &(file->absolute_path[i+1]); - } + i++; + + } while (c != '\0'); + + GUAC_RDP_DEBUG(2, "Initiating download of \"%s\"", + file->absolute_path); + + /* Begin stream */ + guac_protocol_send_file(client->socket, stream, + "application/octet-stream", basename); + guac_socket_flush(client->socket); + + } + else + guac_client_log_error(client, "Unable to download \"%s\"", + file->absolute_path); + + } /* end if download */ /* Close file */ guac_rdp_fs_close((guac_rdp_fs*) device->data, file_id);