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, 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 * An error prevented the operation from writing to its associated
* output stream. * output stream.

View File

@ -143,19 +143,7 @@ typedef struct guac_instruction {
/** /**
* Frees all memory allocated to the given instruction opcode * Frees all memory allocated to the given instruction.
* 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.
* *
* @param instruction The instruction to free. * @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. * Reads a single instruction from the given GUACIO connection.
* *
* If an error occurs reading the instruction, a non-zero value is * If an error occurs reading the instruction, NULL is returned,
* returned, and guac_error is set appropriately. * and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The GUACIO connection to use.
* @param usec_timeout The maximum number of microseconds to wait before * @param usec_timeout The maximum number of microseconds to wait before
* giving up. * giving up.
* @param parsed_instruction A pointer to a guac_instruction structure which * @return A new instruction if data was successfully read, NULL on
* will be populated with data read from the given * error or if the instruction could not be read completely
* GUACIO connection. * because the timeout elapsed, in which case guac_error will be
* @return A positive value if data was successfully read, negative on * set to GUAC_STATUS_INPUT_TIMEOUT and subsequent calls to
* error, or zero if the instruction could not be read completely
* because the timeout elapsed, in which case subsequent calls to
* guac_read_instruction() will return the parsed instruction once * guac_read_instruction() will return the parsed instruction once
* enough data is available. * enough data is available.
*/ */
int guac_read_instruction(GUACIO* io, int usec_timeout, guac_instruction* guac_read_instruction(GUACIO* io, int usec_timeout);
guac_instruction* parsed_instruction);
/** /**
* Returns an arbitrary timestamp. The difference between return values of any * 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; char** argv;
/* Instruction */ /* Instruction */
guac_instruction instruction; guac_instruction* instruction;
/* Wait for select instruction */ /* Wait for select instruction */
for (;;) { for (;;) {
@ -172,19 +172,19 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
return NULL; return NULL;
} }
result = guac_read_instruction(io, usec_timeout, &instruction); instruction = guac_read_instruction(io, usec_timeout);
if (result < 0) { if (instruction == NULL) {
guac_close(io); guac_close(io);
return NULL; return NULL;
} }
/* Select instruction read */ /* Select instruction read */
if (result > 0) { else {
if (strcmp(instruction.opcode, "select") == 0) { if (strcmp(instruction->opcode, "select") == 0) {
/* Get protocol from message */ /* Get protocol from message */
char* protocol = instruction.argv[0]; char* protocol = instruction->argv[0];
strcat(protocol_lib, protocol); strcat(protocol_lib, protocol);
strcat(protocol_lib, ".so"); 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_send_error(io, "Could not load server-side client plugin.");
guac_flush(io); guac_flush(io);
guac_close(io); guac_close(io);
guac_free_instruction_data(&instruction); guac_free_instruction(instruction);
return NULL; 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_send_error(io, "Invalid server-side client plugin.");
guac_flush(io); guac_flush(io);
guac_close(io); guac_close(io);
guac_free_instruction_data(&instruction); guac_free_instruction(instruction);
return NULL; 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_send_error(io, "Invalid server-side client plugin.");
guac_flush(io); guac_flush(io);
guac_close(io); guac_close(io);
guac_free_instruction_data(&instruction); guac_free_instruction(instruction);
return NULL; return NULL;
} }
@ -234,16 +234,16 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
|| guac_flush(io) || guac_flush(io)
) { ) {
guac_close(io); guac_close(io);
guac_free_instruction_data(&instruction); guac_free_instruction(instruction);
return NULL; return NULL;
} }
guac_free_instruction_data(&instruction); guac_free_instruction(instruction);
break; break;
} /* end if select */ } /* 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; return NULL;
} }
result = guac_read_instruction(io, usec_timeout, &instruction); instruction = guac_read_instruction(io, usec_timeout);
if (result < 0) { if (instruction == NULL) {
guac_log_error("Error reading instruction while waiting for connect"); guac_log_error("Error reading instruction while waiting for connect");
guac_close(io); guac_close(io);
return NULL; return NULL;
} }
/* Connect instruction read */ /* Connect instruction read */
if (result > 0) { else {
if (strcmp(instruction.opcode, "connect") == 0) { if (strcmp(instruction->opcode, "connect") == 0) {
/* Initialize client arguments */ /* Initialize client arguments */
argc = instruction.argc; argc = instruction->argc;
argv = instruction.argv; argv = instruction->argv;
if (alias.client_init(client, argc, argv) != 0) { if (alias.client_init(client, argc, argv) != 0) {
/* NOTE: On error, proxy client will send appropriate error message */ /* NOTE: On error, proxy client will send appropriate error message */
guac_free_instruction_data(&instruction); guac_free_instruction(instruction);
guac_close(io); guac_close(io);
return NULL; return NULL;
} }
guac_free_instruction_data(&instruction); guac_free_instruction(instruction);
return client; return client;
} /* end if connect */ } /* 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_MEMORY_STR = "Insufficient memory";
const char* __GUAC_STATUS_NO_INPUT_STR = "End of input stream"; const char* __GUAC_STATUS_NO_INPUT_STR = "End of input stream";
const char* __GUAC_STATUS_INPUT_TIMEOUT_STR = "Read timeout"; 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_OUTPUT_ERROR_STR = "Output error";
const char* __GUAC_STATUS_BAD_ARGUMENT_STR = "Invalid argument"; const char* __GUAC_STATUS_BAD_ARGUMENT_STR = "Invalid argument";
const char* __GUAC_STATUS_BAD_STATE_STR = "Illegal state"; 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: case GUAC_STATUS_INPUT_TIMEOUT:
return __GUAC_STATUS_INPUT_TIMEOUT_STR; return __GUAC_STATUS_INPUT_TIMEOUT_STR;
/* Further information in errno */
case GUAC_STATUS_SEE_ERRNO:
return __GUAC_STATUS_SEE_ERRNO_STR;
/* Output error */ /* Output error */
case GUAC_STATUS_OUTPUT_ERROR: case GUAC_STATUS_OUTPUT_ERROR:
return __GUAC_STATUS_OUTPUT_ERROR_STR; 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 */ /* Record errors in guac_error */
if (retval < 0) if (retval < 0)
guac_error = GUAC_STATUS_OUTPUT_ERROR; guac_error = GUAC_STATUS_SEE_ERRNO;
return retval; return retval;
} }
@ -317,7 +317,7 @@ int guac_select(GUACIO* io, int usec_timeout) {
} }
/* Properly set guac_error */ /* 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; if (retval == 0) guac_error = GUAC_STATUS_INPUT_TIMEOUT;
return retval; return retval;

View File

@ -62,6 +62,7 @@
#include "guacio.h" #include "guacio.h"
#include "protocol.h" #include "protocol.h"
#include "error.h"
ssize_t __guac_write_length_string(GUACIO* io, const char* str) { 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; int retval;
@ -356,8 +357,7 @@ int __guac_fill___instructionbuf(GUACIO* io) {
} }
/* Returns new instruction if one exists, or NULL if no more instructions. */ /* Returns new instruction if one exists, or NULL if no more instructions. */
int guac_read_instruction(GUACIO* io, int usec_timeout, guac_instruction* guac_read_instruction(GUACIO* io, int usec_timeout) {
guac_instruction* parsed_instruction) {
int retval; int retval;
int i = io->__instructionbuf_parse_start; 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 */ /* Finish parse if terminator is a semicolon */
if (terminator == ';') { if (terminator == ';') {
guac_instruction* parsed_instruction;
int j; 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 */ /* Init parsed instruction */
parsed_instruction->argc = io->__instructionbuf_elementc - 1; parsed_instruction->argc = io->__instructionbuf_elementc - 1;
parsed_instruction->argv = malloc(sizeof(char*) * parsed_instruction->argc); 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 */ /* Set opcode */
parsed_instruction->opcode = strdup(io->__instructionbuf_elementv[0]); 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 */ /* 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]); 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 */ /* Reset buffer */
memmove(io->__instructionbuf, io->__instructionbuf + i + 1, io->__instructionbuf_used_length - i - 1); memmove(io->__instructionbuf, io->__instructionbuf + i + 1, io->__instructionbuf_used_length - 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; io->__instructionbuf_elementc = 0;
/* Done */ /* Done */
return 1; return parsed_instruction;
} /* end if terminator */ } /* end if terminator */
@ -444,12 +484,20 @@ int guac_read_instruction(GUACIO* io, int usec_timeout,
/* No instruction yet? Get more data ... */ /* No instruction yet? Get more data ... */
retval = guac_select(io, usec_timeout); retval = guac_select(io, usec_timeout);
if (retval <= 0) if (retval <= 0)
return retval; return NULL;
/* If more data is available, fill into buffer */ /* If more data is available, fill into buffer */
retval = __guac_fill___instructionbuf(io); retval = __guac_fill_instructionbuf(io);
if (retval < 0) return retval; /* Error */
if (retval == 0) return -1; /* EOF */ /* Error, guac_error already set */
if (retval < 0)
return NULL;
/* EOF */
if (retval == 0) {
guac_error = GUAC_STATUS_NO_INPUT;
return NULL;
}
} }