Add abort instruction. Add status codes to abort and error.

This commit is contained in:
Michael Jumper 2013-09-27 19:26:37 -07:00
parent 72d29f18fd
commit cec58edef3
6 changed files with 135 additions and 18 deletions

View File

@ -53,6 +53,66 @@
* @file protocol.h * @file protocol.h
*/ */
/**
* Set of all possible status codes returned by protocol operations. These
* codes relate to Guacamole server/client communication, and not to internal
* communicatin of errors within libguac and linked software.
*
* In general:
*
* 0x0000 - 0x00FF: Successful operations
* 0x0100 - 0x01FF: Operations that failed due to implementation status
* 0x0200 - 0x02FF: Operations that failed due to environmental errors
* 0x0300 - 0x03FF: Operations that failed due to user action
*/
typedef enum guac_protocol_status {
/**
* The operation succeeded.
*/
GUAC_PROTOCOL_STATUS_SUCCESS = 0x0000,
/**
* The requested operation is unsupported.
*/
GUAC_PROTOCOL_STATUS_UNSUPPORTED = 0x0100,
/**
* Permission was denied to perform the operation.
*/
GUAC_PROTOCOL_STATUS_PERMISSION_DENIED = 0x0200,
/**
* The operation could not be performed due to an internal failure of a
* related resource or function.
*/
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR = 0x0201,
/**
* The operation could not be performed due to timeout of a related
* server-side resource.
*/
GUAC_PROTOCOL_STATUS_SERVER_TIMEOUT = 0x0202,
/**
* The operation was canceled. The an operation may be canceled for any
* reason.
*/
GUAC_PROTOCOL_STATUS_CANCELED = 0x0300,
/**
* The operation was unsuccessful due to faulty user input.
*/
GUAC_PROTOCOL_STATUS_INVALID_PARAMETER = 0x0301,
/**
* The operation could not be performed due to timeout of a related
* client-side resource.
*/
GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT = 0x0302
} guac_protocol_status;
/** /**
* Composite modes used by Guacamole draw instructions. Each * Composite modes used by Guacamole draw instructions. Each
* composite mode maps to a unique channel mask integer. * composite mode maps to a unique channel mask integer.
@ -211,10 +271,12 @@ int guac_protocol_send_disconnect(guac_socket* socket);
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param socket The guac_socket connection to use. * @param socket The guac_socket connection to use.
* @param error The description associated with the error. * @param error The human-readable description associated with the error.
* @param status The status code related to the error.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_protocol_send_error(guac_socket* socket, const char* error); int guac_protocol_send_error(guac_socket* socket, const char* error,
guac_protocol_status status);
/** /**
* Sends a nest instruction over the given guac_socket connection. * Sends a nest instruction over the given guac_socket connection.
@ -334,6 +396,22 @@ int guac_protocol_send_file(guac_socket* socket, const guac_stream* stream,
int guac_protocol_send_blob(guac_socket* socket, const guac_stream* stream, int guac_protocol_send_blob(guac_socket* socket, const guac_stream* stream,
void* data, int count); void* data, int count);
/**
* Sends an abort instruction over the given guac_socket connection.
*
* If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately.
*
* @param socket The guac_socket connection to use.
* @param stream The stream to use.
* @param reason The human-readable reason the stream is being aborted.
* @param status The status associated with the reason the stream being
* aborted.
* @return Zero on success, non-zero on error.
*/
int guac_protocol_send_abort(guac_socket* socket, const guac_stream* stream,
const char* reason, guac_protocol_status status);
/** /**
* Sends an end instruction over the given guac_socket connection. * Sends an end instruction over the given guac_socket connection.
* *

View File

@ -355,6 +355,26 @@ int __guac_socket_write_length_png(guac_socket* socket, cairo_surface_t* surface
/* Protocol functions */ /* Protocol functions */
int guac_protocol_send_abort(guac_socket* socket, const guac_stream* stream,
const char* reason, guac_protocol_status status) {
int ret_val;
guac_socket_instruction_begin(socket);
ret_val =
guac_socket_write_string(socket, "5.abort,")
|| __guac_socket_write_length_int(socket, stream->index)
|| guac_socket_write_string(socket, ",")
|| __guac_socket_write_length_string(socket, reason)
|| guac_socket_write_string(socket, ",")
|| __guac_socket_write_length_int(socket, status)
|| guac_socket_write_string(socket, ";");
guac_socket_instruction_end(socket);
return ret_val;
}
static int __guac_protocol_send_args(guac_socket* socket, const char** args) { static int __guac_protocol_send_args(guac_socket* socket, const char** args) {
int i; int i;
@ -751,7 +771,6 @@ int guac_protocol_send_distort(guac_socket* socket, const guac_layer* layer,
} }
int guac_protocol_send_end(guac_socket* socket, const guac_stream* stream) { int guac_protocol_send_end(guac_socket* socket, const guac_stream* stream) {
int ret_val; int ret_val;
@ -768,7 +787,8 @@ int guac_protocol_send_end(guac_socket* socket, const guac_stream* stream) {
} }
int guac_protocol_send_error(guac_socket* socket, const char* error) { int guac_protocol_send_error(guac_socket* socket, const char* error,
guac_protocol_status status) {
int ret_val; int ret_val;
@ -776,6 +796,8 @@ int guac_protocol_send_error(guac_socket* socket, const char* error) {
ret_val = ret_val =
guac_socket_write_string(socket, "5.error,") guac_socket_write_string(socket, "5.error,")
|| __guac_socket_write_length_string(socket, error) || __guac_socket_write_length_string(socket, error)
|| guac_socket_write_string(socket, ",")
|| __guac_socket_write_length_int(socket, status)
|| guac_socket_write_string(socket, ";"); || guac_socket_write_string(socket, ";");
guac_socket_instruction_end(socket); guac_socket_instruction_end(socket);

View File

@ -260,7 +260,9 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
/* Init channels (pre-connect) */ /* Init channels (pre-connect) */
if (freerdp_channels_pre_connect(channels, instance)) { if (freerdp_channels_pre_connect(channels, instance)) {
guac_protocol_send_error(client->socket, "Error initializing RDP client channel manager"); guac_protocol_send_error(client->socket,
"Error initializing RDP client channel manager",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
return FALSE; return FALSE;
} }
@ -277,7 +279,9 @@ BOOL rdp_freerdp_post_connect(freerdp* instance) {
/* Init channels (post-connect) */ /* Init channels (post-connect) */
if (freerdp_channels_post_connect(channels, instance)) { if (freerdp_channels_post_connect(channels, instance)) {
guac_protocol_send_error(client->socket, "Error initializing RDP client channel manager"); guac_protocol_send_error(client->socket,
"Error initializing RDP client channel manager",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
return FALSE; return FALSE;
} }
@ -374,7 +378,8 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
if (argc != RDP_ARGS_COUNT) { if (argc != RDP_ARGS_COUNT) {
guac_protocol_send_error(client->socket, guac_protocol_send_error(client->socket,
"Wrong argument count received."); "Wrong argument count received.",
GUAC_PROTOCOL_STATUS_INVALID_PARAMETER);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
guac_error = GUAC_STATUS_BAD_ARGUMENT; guac_error = GUAC_STATUS_BAD_ARGUMENT;
@ -603,7 +608,8 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
if (!freerdp_connect(rdp_inst)) { if (!freerdp_connect(rdp_inst)) {
guac_protocol_send_error(client->socket, guac_protocol_send_error(client->socket,
"Error connecting to RDP server"); "Error connecting to RDP server",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
guac_error = GUAC_STATUS_BAD_STATE; guac_error = GUAC_STATUS_BAD_STATE;

View File

@ -95,7 +95,8 @@ int ssh_guac_client_handle_messages(guac_client* client) {
/* Notify on error */ /* Notify on error */
if (bytes_read < 0) { if (bytes_read < 0) {
guac_protocol_send_error(socket, "Error reading data."); guac_protocol_send_error(socket, "Error reading data.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket); guac_socket_flush(socket);
return 1; return 1;
} }

View File

@ -162,7 +162,8 @@ void* ssh_client_thread(void* data) {
/* Open SSH session */ /* Open SSH session */
client_data->session = ssh_new(); client_data->session = ssh_new();
if (client_data->session == NULL) { if (client_data->session == NULL) {
guac_protocol_send_error(socket, "Unable to create SSH session."); guac_protocol_send_error(socket, "Unable to create SSH session.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket); guac_socket_flush(socket);
return NULL; return NULL;
} }
@ -174,14 +175,16 @@ void* ssh_client_thread(void* data) {
/* Connect */ /* Connect */
if (ssh_connect(client_data->session) != SSH_OK) { if (ssh_connect(client_data->session) != SSH_OK) {
guac_protocol_send_error(socket, "Unable to connect via SSH."); guac_protocol_send_error(socket, "Unable to connect via SSH.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket); guac_socket_flush(socket);
return NULL; return NULL;
} }
/* Authenticate */ /* Authenticate */
if (ssh_userauth_password(client_data->session, NULL, client_data->password) != SSH_AUTH_SUCCESS) { if (ssh_userauth_password(client_data->session, NULL, client_data->password) != SSH_AUTH_SUCCESS) {
guac_protocol_send_error(socket, "SSH auth failed."); guac_protocol_send_error(socket, "SSH auth failed.",
GUAC_PROTOCOL_STATUS_PERMISSION_DENIED);
guac_socket_flush(socket); guac_socket_flush(socket);
return NULL; return NULL;
} }
@ -189,14 +192,16 @@ void* ssh_client_thread(void* data) {
/* Open channel for terminal */ /* Open channel for terminal */
client_data->term_channel = channel_new(client_data->session); client_data->term_channel = channel_new(client_data->session);
if (client_data->term_channel == NULL) { if (client_data->term_channel == NULL) {
guac_protocol_send_error(socket, "Unable to open channel."); guac_protocol_send_error(socket, "Unable to open channel.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket); guac_socket_flush(socket);
return NULL; return NULL;
} }
/* Open session for channel */ /* Open session for channel */
if (channel_open_session(client_data->term_channel) != SSH_OK) { if (channel_open_session(client_data->term_channel) != SSH_OK) {
guac_protocol_send_error(socket, "Unable to open channel session."); guac_protocol_send_error(socket, "Unable to open channel session.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket); guac_socket_flush(socket);
return NULL; return NULL;
} }
@ -204,14 +209,16 @@ void* ssh_client_thread(void* data) {
/* Request PTY */ /* Request PTY */
if (channel_request_pty_size(client_data->term_channel, "linux", if (channel_request_pty_size(client_data->term_channel, "linux",
client_data->term->term_width, client_data->term->term_height) != SSH_OK) { client_data->term->term_width, client_data->term->term_height) != SSH_OK) {
guac_protocol_send_error(socket, "Unable to allocate PTY for channel."); guac_protocol_send_error(socket, "Unable to allocate PTY for channel.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket); guac_socket_flush(socket);
return NULL; return NULL;
} }
/* Request shell */ /* Request shell */
if (channel_request_shell(client_data->term_channel) != SSH_OK) { if (channel_request_shell(client_data->term_channel) != SSH_OK) {
guac_protocol_send_error(socket, "Unable to associate shell with PTY."); guac_protocol_send_error(socket, "Unable to associate shell with PTY.",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(socket); guac_socket_flush(socket);
return NULL; return NULL;
} }

View File

@ -207,7 +207,9 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
/*** PARSE ARGUMENTS ***/ /*** PARSE ARGUMENTS ***/
if (argc != VNC_ARGS_COUNT) { if (argc != VNC_ARGS_COUNT) {
guac_protocol_send_error(client->socket, "Wrong argument count received."); guac_protocol_send_error(client->socket,
"Wrong argument count received.",
GUAC_PROTOCOL_STATUS_INVALID_PARAMETER);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
return 1; return 1;
} }
@ -290,7 +292,8 @@ int guac_client_init(guac_client* client, int argc, char** argv) {
/* If the final connect attempt fails, return error */ /* If the final connect attempt fails, return error */
if (!rfb_client) { if (!rfb_client) {
guac_protocol_send_error(client->socket, guac_protocol_send_error(client->socket,
"Error initializing VNC client"); "Error initializing VNC client",
GUAC_PROTOCOL_STATUS_INTERNAL_ERROR);
guac_socket_flush(client->socket); guac_socket_flush(client->socket);
return 1; return 1;
} }