Refactor of guac_read_instruction, migrate to new guac_read_instruction

This commit is contained in:
Michael Jumper 2011-11-24 18:18:03 -08:00
parent 5214b1538d
commit 857c2e03c9
6 changed files with 99 additions and 55 deletions

View File

@ -73,6 +73,12 @@ typedef enum guac_status {
*/
GUAC_STATUS_INPUT_TIMEOUT,
/**
* An error occurred, and further information about the error is already
* stored in errno.
*/
GUAC_STATUS_SEE_ERRNO,
/**
* An error prevented the operation from writing to its associated
* output stream.

View File

@ -143,19 +143,7 @@ typedef struct guac_instruction {
/**
* Frees all memory allocated to the given instruction opcode
* and arguments. The instruction structure itself will not
* be freed.
*
* @param instruction The instruction to free.
*/
void guac_free_instruction_data(guac_instruction* instruction);
/**
* Frees all memory allocated to the given instruction. This
* includes freeing memory allocated for the structure
* itself.
* Frees all memory allocated to the given instruction.
*
* @param instruction The instruction to free.
*/
@ -345,23 +333,20 @@ int guac_instructions_waiting(GUACIO* io, int usec_timeout);
/**
* Reads a single instruction from the given GUACIO connection.
*
* If an error occurs reading the instruction, a non-zero value is
* returned, and guac_error is set appropriately.
* If an error occurs reading the instruction, NULL is returned,
* and guac_error is set appropriately.
*
* @param io The GUACIO connection to use.
* @param usec_timeout The maximum number of microseconds to wait before
* giving up.
* @param parsed_instruction A pointer to a guac_instruction structure which
* will be populated with data read from the given
* GUACIO connection.
* @return A positive value if data was successfully read, negative on
* error, or zero if the instruction could not be read completely
* because the timeout elapsed, in which case subsequent calls to
* @return A new instruction if data was successfully read, NULL on
* error or if the instruction could not be read completely
* because the timeout elapsed, in which case guac_error will be
* set to GUAC_STATUS_INPUT_TIMEOUT and subsequent calls to
* guac_read_instruction() will return the parsed instruction once
* enough data is available.
*/
int guac_read_instruction(GUACIO* io, int usec_timeout,
guac_instruction* parsed_instruction);
guac_instruction* guac_read_instruction(GUACIO* io, int usec_timeout);
/**
* Returns an arbitrary timestamp. The difference between return values of any

View File

@ -151,7 +151,7 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
char** argv;
/* Instruction */
guac_instruction instruction;
guac_instruction* instruction;
/* Wait for select instruction */
for (;;) {
@ -172,19 +172,19 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
return NULL;
}
result = guac_read_instruction(io, usec_timeout, &instruction);
if (result < 0) {
instruction = guac_read_instruction(io, usec_timeout);
if (instruction == NULL) {
guac_close(io);
return NULL;
}
/* Select instruction read */
if (result > 0) {
else {
if (strcmp(instruction.opcode, "select") == 0) {
if (strcmp(instruction->opcode, "select") == 0) {
/* Get protocol from message */
char* protocol = instruction.argv[0];
char* protocol = instruction->argv[0];
strcat(protocol_lib, protocol);
strcat(protocol_lib, ".so");
@ -199,7 +199,7 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
guac_send_error(io, "Could not load server-side client plugin.");
guac_flush(io);
guac_close(io);
guac_free_instruction_data(&instruction);
guac_free_instruction(instruction);
return NULL;
}
@ -213,7 +213,7 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
guac_send_error(io, "Invalid server-side client plugin.");
guac_flush(io);
guac_close(io);
guac_free_instruction_data(&instruction);
guac_free_instruction(instruction);
return NULL;
}
@ -225,7 +225,7 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
guac_send_error(io, "Invalid server-side client plugin.");
guac_flush(io);
guac_close(io);
guac_free_instruction_data(&instruction);
guac_free_instruction(instruction);
return NULL;
}
@ -234,16 +234,16 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
|| guac_flush(io)
) {
guac_close(io);
guac_free_instruction_data(&instruction);
guac_free_instruction(instruction);
return NULL;
}
guac_free_instruction_data(&instruction);
guac_free_instruction(instruction);
break;
} /* end if select */
guac_free_instruction_data(&instruction);
guac_free_instruction(instruction);
}
}
@ -267,35 +267,35 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
return NULL;
}
result = guac_read_instruction(io, usec_timeout, &instruction);
if (result < 0) {
instruction = guac_read_instruction(io, usec_timeout);
if (instruction == NULL) {
guac_log_error("Error reading instruction while waiting for connect");
guac_close(io);
return NULL;
}
/* Connect instruction read */
if (result > 0) {
else {
if (strcmp(instruction.opcode, "connect") == 0) {
if (strcmp(instruction->opcode, "connect") == 0) {
/* Initialize client arguments */
argc = instruction.argc;
argv = instruction.argv;
argc = instruction->argc;
argv = instruction->argv;
if (alias.client_init(client, argc, argv) != 0) {
/* NOTE: On error, proxy client will send appropriate error message */
guac_free_instruction_data(&instruction);
guac_free_instruction(instruction);
guac_close(io);
return NULL;
}
guac_free_instruction_data(&instruction);
guac_free_instruction(instruction);
return client;
} /* end if connect */
guac_free_instruction_data(&instruction);
guac_free_instruction(instruction);
}
}

View File

@ -49,6 +49,7 @@ const char* __GUAC_STATUS_SUCCESS_STR = "Success";
const char* __GUAC_STATUS_NO_MEMORY_STR = "Insufficient memory";
const char* __GUAC_STATUS_NO_INPUT_STR = "End of input stream";
const char* __GUAC_STATUS_INPUT_TIMEOUT_STR = "Read timeout";
const char* __GUAC_STATUS_SEE_ERRNO_STR = "(see value of errno)";
const char* __GUAC_STATUS_OUTPUT_ERROR_STR = "Output error";
const char* __GUAC_STATUS_BAD_ARGUMENT_STR = "Invalid argument";
const char* __GUAC_STATUS_BAD_STATE_STR = "Illegal state";
@ -75,6 +76,10 @@ const char* guac_status_string(guac_status status) {
case GUAC_STATUS_INPUT_TIMEOUT:
return __GUAC_STATUS_INPUT_TIMEOUT_STR;
/* Further information in errno */
case GUAC_STATUS_SEE_ERRNO:
return __GUAC_STATUS_SEE_ERRNO_STR;
/* Output error */
case GUAC_STATUS_OUTPUT_ERROR:
return __GUAC_STATUS_OUTPUT_ERROR_STR;

View File

@ -117,7 +117,7 @@ ssize_t __guac_write(GUACIO* io, const char* buf, int count) {
/* Record errors in guac_error */
if (retval < 0)
guac_error = GUAC_STATUS_OUTPUT_ERROR;
guac_error = GUAC_STATUS_SEE_ERRNO;
return retval;
}
@ -317,7 +317,7 @@ int guac_select(GUACIO* io, int usec_timeout) {
}
/* Properly set guac_error */
if (retval < 0) guac_error = GUAC_STATUS_INPUT_ERROR;
if (retval < 0) guac_error = GUAC_STATUS_SEE_ERRNO;
if (retval == 0) guac_error = GUAC_STATUS_INPUT_TIMEOUT;
return retval;

View File

@ -62,6 +62,7 @@
#include "guacio.h"
#include "protocol.h"
#include "error.h"
ssize_t __guac_write_length_string(GUACIO* io, const char* str) {
@ -328,7 +329,7 @@ int guac_send_cursor(GUACIO* io, int x, int y, cairo_surface_t* surface) {
}
int __guac_fill___instructionbuf(GUACIO* io) {
int __guac_fill_instructionbuf(GUACIO* io) {
int retval;
@ -356,8 +357,7 @@ int __guac_fill___instructionbuf(GUACIO* io) {
}
/* Returns new instruction if one exists, or NULL if no more instructions. */
int guac_read_instruction(GUACIO* io, int usec_timeout,
guac_instruction* parsed_instruction) {
guac_instruction* guac_read_instruction(GUACIO* io, int usec_timeout) {
int retval;
int i = io->__instructionbuf_parse_start;
@ -407,19 +407,59 @@ int guac_read_instruction(GUACIO* io, int usec_timeout,
/* Finish parse if terminator is a semicolon */
if (terminator == ';') {
guac_instruction* parsed_instruction;
int j;
/* Allocate instruction */
parsed_instruction = malloc(sizeof(guac_instruction));
if (parsed_instruction == NULL) {
guac_error = GUAC_STATUS_NO_MEMORY;
return NULL;
}
/* Init parsed instruction */
parsed_instruction->argc = io->__instructionbuf_elementc - 1;
parsed_instruction->argv = malloc(sizeof(char*) * parsed_instruction->argc);
/* Fail if memory could not be alloc'd for argv */
if (parsed_instruction->argv == NULL) {
guac_error = GUAC_STATUS_NO_MEMORY;
free(parsed_instruction);
return NULL;
}
/* Set opcode */
parsed_instruction->opcode = strdup(io->__instructionbuf_elementv[0]);
/* Fail if memory could not be alloc'd for opcode */
if (parsed_instruction->opcode == NULL) {
guac_error = GUAC_STATUS_NO_MEMORY;
free(parsed_instruction->argv);
free(parsed_instruction);
return NULL;
}
/* Copy element values to parsed instruction */
for (j=0; j<parsed_instruction->argc; j++)
for (j=0; j<parsed_instruction->argc; j++) {
parsed_instruction->argv[j] = strdup(io->__instructionbuf_elementv[j+1]);
/* Free memory and fail if out of mem */
if (parsed_instruction->argv[j] == NULL) {
guac_error = GUAC_STATUS_NO_MEMORY;
/* Free all alloc'd argv values */
while (--j >= 0)
free(parsed_instruction->argv[j]);
free(parsed_instruction->opcode);
free(parsed_instruction->argv);
free(parsed_instruction);
return NULL;
}
}
/* Reset buffer */
memmove(io->__instructionbuf, io->__instructionbuf + i + 1, io->__instructionbuf_used_length - i - 1);
io->__instructionbuf_used_length -= i + 1;
@ -427,7 +467,7 @@ int guac_read_instruction(GUACIO* io, int usec_timeout,
io->__instructionbuf_elementc = 0;
/* Done */
return 1;
return parsed_instruction;
} /* end if terminator */
@ -444,12 +484,20 @@ int guac_read_instruction(GUACIO* io, int usec_timeout,
/* No instruction yet? Get more data ... */
retval = guac_select(io, usec_timeout);
if (retval <= 0)
return retval;
return NULL;
/* If more data is available, fill into buffer */
retval = __guac_fill___instructionbuf(io);
if (retval < 0) return retval; /* Error */
if (retval == 0) return -1; /* EOF */
retval = __guac_fill_instructionbuf(io);
/* Error, guac_error already set */
if (retval < 0)
return NULL;
/* EOF */
if (retval == 0) {
guac_error = GUAC_STATUS_NO_INPUT;
return NULL;
}
}