int __guac_fill_instructionbuf(guac_socket* socket) { int retval; /* Attempt to fill buffer */ retval = guac_socket_read( socket, socket->__instructionbuf + socket->__instructionbuf_used_length, socket->__instructionbuf_size - socket->__instructionbuf_used_length ); /* Set guac_error if recv() unsuccessful */ if (retval < 0) { guac_error = GUAC_STATUS_SEE_ERRNO; guac_error_message = "Error filling instruction buffer"; return retval; } socket->__instructionbuf_used_length += retval; /* Expand buffer if necessary */ if (socket->__instructionbuf_used_length > socket->__instructionbuf_size / 2) { socket->__instructionbuf_size *= 2; socket->__instructionbuf = realloc(socket->__instructionbuf, socket->__instructionbuf_size); } return retval; }
int guac_parser_read(guac_parser* parser, guac_socket* socket, int usec_timeout) { char* unparsed_end = parser->__instructionbuf_unparsed_end; char* unparsed_start = parser->__instructionbuf_unparsed_start; char* instr_start = parser->__instructionbuf_unparsed_start; char* buffer_end = parser->__instructionbuf + sizeof(parser->__instructionbuf); /* Begin next instruction if previous was ended */ if (parser->state == GUAC_PARSE_COMPLETE) guac_parser_reset(parser); while (parser->state != GUAC_PARSE_COMPLETE && parser->state != GUAC_PARSE_ERROR) { /* Add any available data to buffer */ int parsed = guac_parser_append(parser, unparsed_start, unparsed_end - unparsed_start); /* Read more data if not enough data to parse */ if (parsed == 0 && parser->state != GUAC_PARSE_ERROR) { int retval; /* If no space left to read, fail */ if (unparsed_end == buffer_end) { /* Shift backward if possible */ if (instr_start != parser->__instructionbuf) { int i; /* Shift buffer */ int offset = instr_start - parser->__instructionbuf; memmove(parser->__instructionbuf, instr_start, unparsed_end - instr_start); /* Update tracking pointers */ unparsed_end -= offset; unparsed_start -= offset; instr_start = parser->__instructionbuf; /* Update parsed elements, if any */ for (i=0; i < parser->__elementc; i++) parser->__elementv[i] -= offset; } /* Otherwise, no memory to read */ else { guac_error = GUAC_STATUS_NO_MEMORY; guac_error_message = "Instruction too long"; return -1; } } /* No instruction yet? Get more data ... */ retval = guac_socket_select(socket, usec_timeout); if (retval <= 0) return -1; /* Attempt to fill buffer */ retval = guac_socket_read(socket, unparsed_end, buffer_end - unparsed_end); /* Set guac_error if read unsuccessful */ if (retval < 0) { guac_error = GUAC_STATUS_SEE_ERRNO; guac_error_message = "Error filling instruction buffer"; return -1; } /* EOF */ if (retval == 0) { guac_error = GUAC_STATUS_CLOSED; guac_error_message = "End of stream reached while " "reading instruction"; return -1; } /* Update internal buffer */ unparsed_end += retval; } /* If data was parsed, advance buffer */ else unparsed_start += parsed; } /* end while parsing data */ /* Fail on error */ if (parser->state == GUAC_PARSE_ERROR) { guac_error = GUAC_STATUS_PROTOCOL_ERROR; guac_error_message = "Instruction parse error"; return -1; } parser->__instructionbuf_unparsed_start = unparsed_start; parser->__instructionbuf_unparsed_end = unparsed_end; return 0; }
/* Returns new instruction if one exists, or NULL if no more instructions. */ guac_instruction* guac_instruction_read(guac_socket* socket, int usec_timeout) { char* unparsed_end = socket->__instructionbuf_unparsed_end; char* unparsed_start = socket->__instructionbuf_unparsed_start; char* instr_start = socket->__instructionbuf_unparsed_start; char* buffer_end = socket->__instructionbuf + sizeof(socket->__instructionbuf); guac_instruction* instruction = guac_instruction_alloc(); while (instruction->state != GUAC_INSTRUCTION_PARSE_COMPLETE && instruction->state != GUAC_INSTRUCTION_PARSE_ERROR) { /* Add any available data to buffer */ int parsed = guac_instruction_append(instruction, unparsed_start, unparsed_end - unparsed_start); /* Read more data if not enough data to parse */ if (parsed == 0) { int retval; /* If no space left to read, fail */ if (unparsed_end == buffer_end) { /* Shift backward if possible */ if (instr_start != socket->__instructionbuf) { int i; /* Shift buffer */ int offset = instr_start - socket->__instructionbuf; memmove(socket->__instructionbuf, instr_start, unparsed_end - instr_start); /* Update tracking pointers */ unparsed_end -= offset; unparsed_start -= offset; instr_start = socket->__instructionbuf; /* Update parsed elements, if any */ for (i=0; i<instruction->__elementc; i++) instruction->__elementv[i] -= offset; } /* Otherwise, no memory to read */ else { guac_error = GUAC_STATUS_NO_MEMORY; guac_error_message = "Instruction too long"; return NULL; } } /* No instruction yet? Get more data ... */ retval = guac_socket_select(socket, usec_timeout); if (retval <= 0) return NULL; /* Attempt to fill buffer */ retval = guac_socket_read(socket, unparsed_end, buffer_end - unparsed_end); /* Set guac_error if read unsuccessful */ if (retval < 0) { guac_error = GUAC_STATUS_SEE_ERRNO; guac_error_message = "Error filling instruction buffer"; return NULL; } /* EOF */ if (retval == 0) { guac_error = GUAC_STATUS_NO_INPUT; guac_error_message = "End of stream reached while " "reading instruction"; return NULL; } /* Update internal buffer */ unparsed_end += retval; } /* If data was parsed, advance buffer */ else unparsed_start += parsed; } /* end while parsing data */ /* Fail on error */ if (instruction->state == GUAC_INSTRUCTION_PARSE_ERROR) { guac_error = GUAC_STATUS_BAD_ARGUMENT; guac_error_message = "Instruction parse error"; return NULL; } socket->__instructionbuf_unparsed_start = unparsed_start; socket->__instructionbuf_unparsed_end = unparsed_end; return instruction; }