/** * 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; }
/** * Callback which is invoked by guac_client_foreach_user() to flush all * pending data on the given user's socket. If an error occurs while flushing * a user's socket, that user is signalled to stop with guac_user_stop(). * * @param user * The user whose socket should be flushed. * * @param data * Arbitrary data passed to guac_client_foreach_user(). This is not needed * by this callback, and should be left as NULL. * * @return * Always NULL. */ static void* __flush_callback(guac_user* user, void* data) { /* Attempt flush, disconnect on failure */ if (guac_socket_flush(user->socket)) guac_user_stop(user); return NULL; }
/** * Callback invoked by guac_client_foreach_user() which write a given chunk of * data to that user's socket. If the write attempt fails, the user is * signalled to stop with guac_user_stop(). * * @param user * The user that the chunk of data should be written to. * * @param data * A pointer to a __write_chunk which describes the data to be written. * * @return * Always NULL. */ static void* __write_chunk_callback(guac_user* user, void* data) { __write_chunk* chunk = (__write_chunk*) data; /* Attempt write, disconnect on failure */ if (guac_socket_write(user->socket, chunk->buffer, chunk->length)) guac_user_stop(user); return NULL; }