Add typing to stream data.

This commit is contained in:
Michael Jumper 2014-03-02 11:52:36 -08:00
parent 38e4c9afba
commit e37c5c462f
4 changed files with 184 additions and 115 deletions

View File

@ -30,6 +30,7 @@
#include "rdp_fs.h" #include "rdp_fs.h"
#include "rdp_keymap.h" #include "rdp_keymap.h"
#include "rdp_settings.h" #include "rdp_settings.h"
#include "rdp_svc.h"
#include <pthread.h> #include <pthread.h>
@ -219,6 +220,73 @@ typedef struct guac_rdp_download_status {
} guac_rdp_download_status; } guac_rdp_download_status;
/**
* Structure which represents the current state of an upload.
*/
typedef struct guac_rdp_upload_status {
/**
* The overall offset within the file that the next write should
* occur at.
*/
int offset;
/**
* The ID of the file being written to.
*/
int file_id;
} guac_rdp_upload_status;
/**
* All available stream types.
*/
typedef enum guac_rdp_stream_type {
/**
* An in-progress file upload.
*/
GUAC_RDP_UPLOAD_STREAM,
/**
* An in-progress file download.
*/
GUAC_RDP_DOWNLOAD_STREAM,
/**
* The inbound half of a static virtual channel.
*/
GUAC_RDP_INBOUND_SVC_STREAM
} guac_rdp_stream_type;
/**
* Variable-typed stream data.
*/
typedef struct guac_rdp_stream {
/**
* The type of this stream.
*/
guac_rdp_stream_type type;
/**
* The file upload status. Only valid for GUAC_RDP_UPLOAD_STREAM.
*/
guac_rdp_upload_status upload_status;
/**
* The file upload status. Only valid for GUAC_RDP_DOWNLOAD_STREAM.
*/
guac_rdp_download_status download_status;
/**
* Associated SVC instance. Only valid for GUAC_RDP_SVC_STREAM.
*/
guac_rdp_svc* svc;
} guac_rdp_stream;
/** /**
* Given the coordinates and dimensions of a rectangle, clips the rectangle to be * 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. * within the clipping bounds of the client data, if clipping is active.

View File

@ -527,7 +527,7 @@ int rdp_guac_client_file_handler(guac_client* client, guac_stream* stream,
char* mimetype, char* filename) { char* mimetype, char* filename) {
int file_id; int file_id;
guac_rdp_upload_stat* stat; guac_rdp_stream* rdp_stream;
char file_path[GUAC_RDP_FS_MAX_PATH]; char file_path[GUAC_RDP_FS_MAX_PATH];
/* Get filesystem, return error if no filesystem */ /* Get filesystem, return error if no filesystem */
@ -553,147 +553,165 @@ int rdp_guac_client_file_handler(guac_client* client, guac_stream* stream,
} }
/* Init upload status */ /* Init upload status */
stat = malloc(sizeof(guac_rdp_upload_stat)); rdp_stream = malloc(sizeof(guac_rdp_stream));
stat->offset = 0; rdp_stream->type = GUAC_RDP_UPLOAD_STREAM;
stat->file_id = file_id; rdp_stream->upload_status.offset = 0;
stream->data = stat; rdp_stream->upload_status.file_id = file_id;
stream->data = rdp_stream;
guac_protocol_send_ack(client->socket, stream, "OK (STREAM BEGIN)", guac_protocol_send_ack(client->socket, stream, "OK (STREAM BEGIN)",
GUAC_PROTOCOL_STATUS_SUCCESS); GUAC_PROTOCOL_STATUS_SUCCESS);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
return 0; return 0;
} }
int rdp_guac_client_blob_handler(guac_client* client, guac_stream* stream, int rdp_guac_client_blob_handler(guac_client* client, guac_stream* stream,
void* data, int length) { void* data, int length) {
int bytes_written; int bytes_written;
guac_rdp_upload_stat* stat; guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;
/* Get filesystem, return error if no filesystem */ /* Write any received data if upload stream */
guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem; if (rdp_stream->type == GUAC_RDP_UPLOAD_STREAM) {
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;
}
/* Get upload status */ /* Get filesystem, return error if no filesystem 0*/
stat = (guac_rdp_upload_stat*) stream->data; guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
if (fs == NULL) {
/* Write entire block */ guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)",
while (length > 0) { GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
/* Attempt write */
bytes_written = guac_rdp_fs_write(fs, stat->file_id, stat->offset,
data, length);
/* On error, abort */
if (bytes_written < 0) {
guac_protocol_send_ack(client->socket, stream, "FAIL (BAD WRITE)",
GUAC_PROTOCOL_STATUS_PERMISSION_DENIED);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
return 0; return 0;
} }
/* Update counters */ /* Write entire block */
stat->offset += bytes_written; while (length > 0) {
data += bytes_written;
length -= bytes_written;
} /* Attempt write */
bytes_written = guac_rdp_fs_write(fs,
rdp_stream->upload_status.file_id,
rdp_stream->upload_status.offset,
data, length);
guac_protocol_send_ack(client->socket, stream, "OK (DATA WRITTEN)", /* On error, abort */
if (bytes_written < 0) {
guac_protocol_send_ack(client->socket, stream,
"FAIL (BAD WRITE)",
GUAC_PROTOCOL_STATUS_PERMISSION_DENIED);
guac_socket_flush(client->socket);
return 0;
}
/* Update counters */
rdp_stream->upload_status.offset += bytes_written;
data += bytes_written;
length -= bytes_written;
}
} /* end if upload stream */
guac_protocol_send_ack(client->socket, stream, "OK (DATA RECEIVED)",
GUAC_PROTOCOL_STATUS_SUCCESS); GUAC_PROTOCOL_STATUS_SUCCESS);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
return 0; return 0;
} }
int rdp_guac_client_end_handler(guac_client* client, guac_stream* stream) { int rdp_guac_client_end_handler(guac_client* client, guac_stream* stream) {
guac_rdp_upload_stat* stat; guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;
/* Close file for upload streams */
if (rdp_stream->type == GUAC_RDP_UPLOAD_STREAM) {
/* 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;
}
/* Close file */
guac_rdp_fs_close(fs, rdp_stream->upload_status.file_id);
/* 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;
} }
/* Get upload status */ /* Acknowledge stream end */
stat = (guac_rdp_upload_stat*) stream->data;
/* Close file */
guac_rdp_fs_close(fs, stat->file_id);
free(stat);
guac_protocol_send_ack(client->socket, stream, "OK (STREAM END)", guac_protocol_send_ack(client->socket, stream, "OK (STREAM END)",
GUAC_PROTOCOL_STATUS_SUCCESS); GUAC_PROTOCOL_STATUS_SUCCESS);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
free(rdp_stream);
return 0; return 0;
} }
int rdp_guac_client_ack_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) { char* message, guac_protocol_status status) {
/* Get status */ guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data;
guac_rdp_download_status* download =
(guac_rdp_download_status*) stream->data;
/* Ignore acks for non-download stream data */ /* Ignore acks for non-download stream data */
if (download == NULL) if (rdp_stream == NULL)
return 0; return 0;
/* Get filesystem, return error if no filesystem */ /* Send more data when download blobs are acknowledged */
guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem; if (rdp_stream->type == GUAC_RDP_DOWNLOAD_STREAM) {
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 */ /* Get filesystem, return error if no filesystem */
if (status == GUAC_PROTOCOL_STATUS_SUCCESS) { guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem;
if (fs == NULL) {
/* Attempt read into buffer */ guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)",
char buffer[4096]; GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
int bytes_read = guac_rdp_fs_read(fs, download->file_id, guac_socket_flush(client->socket);
download->offset, buffer, sizeof(buffer)); return 0;
/* 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 */ /* If successful, read data */
else if (bytes_read == 0) { if (status == GUAC_PROTOCOL_STATUS_SUCCESS) {
guac_protocol_send_end(client->socket, stream);
/* Attempt read into buffer */
char buffer[4096];
int bytes_read = guac_rdp_fs_read(fs,
rdp_stream->download_status.file_id,
rdp_stream->download_status.offset, buffer, sizeof(buffer));
/* If bytes read, send as blob */
if (bytes_read > 0) {
rdp_stream->download_status.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);
free(rdp_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);
free(rdp_stream);
}
guac_socket_flush(client->socket);
}
/* Otherwise, return stream to client */
else
guac_client_free_stream(client, stream); guac_client_free_stream(client, stream);
free(download);
}
/* 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);
free(download);
}
guac_socket_flush(client->socket);
} }
/* Otherwise, return stream to client */
else
guac_client_free_stream(client, stream);
return 0; return 0;
} }

View File

@ -29,24 +29,6 @@
#include <guacamole/client.h> #include <guacamole/client.h>
#include <guacamole/stream.h> #include <guacamole/stream.h>
/**
* Structure which represents the current state of an upload.
*/
typedef struct guac_rdp_upload_stat {
/**
* The overall offset within the file that the next write should
* occur at.
*/
int offset;
/**
* The ID of the file being written to.
*/
int file_id;
} guac_rdp_upload_stat;
int rdp_guac_client_free_handler(guac_client* client); int rdp_guac_client_free_handler(guac_client* client);
int rdp_guac_client_handle_messages(guac_client* client); int rdp_guac_client_handle_messages(guac_client* client);
int rdp_guac_client_mouse_handler(guac_client* client, int x, int y, int mask); int rdp_guac_client_mouse_handler(guac_client* client, int x, int y, int mask);

View File

@ -230,7 +230,7 @@ void guac_rdpdr_start_download(guac_rdpdr_device* device, const char* path) {
/* If file opened successfully, start stream */ /* If file opened successfully, start stream */
if (file_id >= 0) { if (file_id >= 0) {
guac_rdp_download_status* status; guac_rdp_stream* rdp_stream;
const char* basename; const char* basename;
int i; int i;
@ -238,9 +238,10 @@ void guac_rdpdr_start_download(guac_rdpdr_device* device, const char* path) {
/* Associate stream with transfer status */ /* Associate stream with transfer status */
guac_stream* stream = guac_client_alloc_stream(client); guac_stream* stream = guac_client_alloc_stream(client);
stream->data = status = malloc(sizeof(guac_rdp_download_status)); stream->data = rdp_stream = malloc(sizeof(guac_rdp_stream));
status->file_id = file_id; rdp_stream->type = GUAC_RDP_DOWNLOAD_STREAM;
status->offset = 0; rdp_stream->download_status.file_id = file_id;
rdp_stream->download_status.offset = 0;
/* Get basename from absolute path */ /* Get basename from absolute path */
i=0; i=0;