/** * Reads and handles all Guacamole instructions from the given guac_socket * until end-of-stream is reached. * * @param state * The current state of the Guacamole input log interpreter. * * @param path * The name of the file being parsed (for logging purposes). This file * must already be open and available through the given socket. * * @param socket * The guac_socket through which instructions should be read. * * @return * Zero on success, non-zero if parsing of Guacamole protocol data through * the given socket fails. */ static int guaclog_read_instructions(guaclog_state* state, const char* path, guac_socket* socket) { /* Obtain Guacamole protocol parser */ guac_parser* parser = guac_parser_alloc(); if (parser == NULL) return 1; /* Continuously read and handle all instructions */ while (!guac_parser_read(parser, socket, -1)) { guaclog_handle_instruction(state, parser->opcode, parser->argc, parser->argv); } /* Fail on read/parse error */ if (guac_error != GUAC_STATUS_CLOSED) { guaclog_log(GUAC_LOG_ERROR, "%s: %s", path, guac_status_string(guac_error)); guac_parser_free(parser); return 1; } /* Parse complete */ guac_parser_free(parser); return 0; }
/** * The thread which handles all user input, calling event handlers for received * instructions. * * @param data * A pointer to a guac_user_input_thread_params structure describing the * user whose input is being handled and the guac_parser with which to * handle it. * * @return * Always NULL. */ static void* guac_user_input_thread(void* data) { guac_user_input_thread_params* params = (guac_user_input_thread_params*) data; int usec_timeout = params->usec_timeout; guac_user* user = params->user; guac_parser* parser = params->parser; guac_client* client = user->client; guac_socket* socket = user->socket; /* Guacamole user input loop */ while (client->state == GUAC_CLIENT_RUNNING && user->active) { /* Read instruction, stop on error */ if (guac_parser_read(parser, socket, usec_timeout)) { if (guac_error == GUAC_STATUS_TIMEOUT) guac_user_abort(user, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "User is not responding."); else { if (guac_error != GUAC_STATUS_CLOSED) guac_user_log_guac_error(user, GUAC_LOG_WARNING, "Guacamole connection failure"); guac_user_stop(user); } return NULL; } /* Reset guac_error and guac_error_message (user/client handlers are not * guaranteed to set these) */ guac_error = GUAC_STATUS_SUCCESS; guac_error_message = NULL; /* Call handler, stop on error */ if (guac_user_handle_instruction(user, parser->opcode, parser->argc, parser->argv) < 0) { /* Log error */ guac_user_log_guac_error(user, GUAC_LOG_WARNING, "User connection aborted"); /* Log handler details */ guac_user_log(user, GUAC_LOG_DEBUG, "Failing instruction handler in user was \"%s\"", parser->opcode); guac_user_stop(user); return NULL; } } return NULL; }
int guac_parser_expect(guac_parser* parser, guac_socket* socket, int usec_timeout, const char* opcode) { /* Read next instruction */ if (guac_parser_read(parser, socket, usec_timeout) != 0) return -1; /* Validate instruction */ if (strcmp(parser->opcode, opcode) != 0) { guac_error = GUAC_STATUS_PROTOCOL_ERROR; guac_error_message = "Instruction read did not have expected opcode"; return -1; } /* Return non-zero only if valid instruction read */ return parser->state != GUAC_PARSE_COMPLETE; }