Example #1
0
void* __guacd_client_input_thread(void* data) {

    guac_client* client = (guac_client*) data;
    guac_socket* socket = client->socket;

    /* Guacamole client input loop */
    while (client->state == GUAC_CLIENT_RUNNING) {

        /* Read instruction */
        guac_instruction* instruction =
            guac_instruction_read(socket, GUACD_USEC_TIMEOUT);

        /* Stop on error */
        if (instruction == NULL) {

            if (guac_error == GUAC_STATUS_INPUT_TIMEOUT)
                guac_client_abort(client, GUAC_PROTOCOL_STATUS_CLIENT_TIMEOUT, "Client is not responding.");

            else {
                guacd_client_log_guac_error(client, "Error reading instruction");
                guac_client_stop(client);
            }

            return NULL;
        }

        /* Reset guac_error and guac_error_message (client handlers are not
         * guaranteed to set these) */
        guac_error = GUAC_STATUS_SUCCESS;
        guac_error_message = NULL;

        /* Call handler, stop on error */
        if (guac_client_handle_instruction(client, instruction) < 0) {

            /* Log error */
            guacd_client_log_guac_error(client,
                    "Client instruction handler error");

            /* Log handler details */
            guac_client_log(client, GUAC_LOG_INFO,
                    "Failing instruction handler in client was \"%s\"",
                    instruction->opcode);

            guac_instruction_free(instruction);
            guac_client_stop(client);
            return NULL;
        }

        /* Free allocated instruction */
        guac_instruction_free(instruction);

    }

    return NULL;

}
Example #2
0
guac_instruction* guac_instruction_expect(guac_socket* socket, int usec_timeout,
        const char* opcode) {

    guac_instruction* instruction;

    /* Wait for data until timeout */
    if (guac_instruction_waiting(socket, usec_timeout) <= 0)
        return NULL;

    /* Read available instruction */
    instruction = guac_instruction_read(socket, usec_timeout);
    if (instruction == NULL)
        return NULL;            

    /* Validate instruction */
    if (strcmp(instruction->opcode, opcode) != 0) {
        guac_error = GUAC_STATUS_BAD_STATE;
        guac_error_message = "Instruction read did not have expected opcode";
        guac_instruction_free(instruction);
        return NULL;
    }

    /* Return instruction if valid */
    return instruction;

}
Example #3
0
/**
 * Creates a new guac_client for the connection on the given socket, adding
 * it to the client map based on its ID.
 */
static void guacd_handle_connection(guacd_client_map* map, guac_socket* socket) {

    guac_client* client;
    guac_client_plugin* plugin;
    guac_instruction* select;
    guac_instruction* size;
    guac_instruction* audio;
    guac_instruction* video;
    guac_instruction* connect;
    int init_result;

    /* Reset guac_error */
    guac_error = GUAC_STATUS_SUCCESS;
    guac_error_message = NULL;

    /* Get protocol from select instruction */
    select = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "select");
    if (select == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"select\"");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Validate args to select */
    if (select->argc != 1) {

        /* Log error */
        guacd_log_error("Bad number of arguments to \"select\" (%i)",
                select->argc);

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    guacd_log_info("Protocol \"%s\" selected", select->argv[0]);

    /* Get plugin from protocol in select */
    plugin = guac_client_plugin_open(select->argv[0]);
    guac_instruction_free(select);

    if (plugin == NULL) {

        /* Log error */
        guacd_log_guac_error("Error loading client plugin");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Send args response */
    if (guac_protocol_send_args(socket, plugin->args)
            || guac_socket_flush(socket)) {

        /* Log error */
        guacd_log_guac_error("Error sending \"args\"");

        if (guac_client_plugin_close(plugin))
            guacd_log_guac_error("Error closing client plugin");

        guac_socket_free(socket);
        return;
    }

    /* Get optimal screen size */
    size = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "size");
    if (size == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"size\"");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Get supported audio formats */
    audio = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "audio");
    if (audio == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"audio\"");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Get supported video formats */
    video = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "video");
    if (video == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"video\"");

        /* Free resources */
        guac_socket_free(socket);
        return;
    }

    /* Get args from connect instruction */
    connect = guac_instruction_expect(
            socket, GUACD_USEC_TIMEOUT, "connect");
    if (connect == NULL) {

        /* Log error */
        guacd_log_guac_error("Error reading \"connect\"");

        if (guac_client_plugin_close(plugin))
            guacd_log_guac_error("Error closing client plugin");

        guac_socket_free(socket);
        return;
    }

    /* Get client */
    client = guac_client_alloc();
    if (client == NULL) {
        guacd_log_guac_error("Client could not be allocated");
        guac_socket_free(socket);
        return;
    }

    client->socket = socket;
    client->log_info_handler = guacd_client_log_info;
    client->log_error_handler = guacd_client_log_error;

    /* Parse optimal screen dimensions from size instruction */
    client->info.optimal_width  = atoi(size->argv[0]);
    client->info.optimal_height = atoi(size->argv[1]);

    /* If DPI given, set the client resolution */
    if (size->argc >= 3)
        client->info.optimal_resolution = atoi(size->argv[2]);

    /* Otherwise, use a safe default for rough backwards compatibility */
    else
        client->info.optimal_resolution = 96;

    /* Store audio mimetypes */
    client->info.audio_mimetypes = malloc(sizeof(char*) * (audio->argc+1));
    memcpy(client->info.audio_mimetypes, audio->argv,
            sizeof(char*) * audio->argc);
    client->info.audio_mimetypes[audio->argc] = NULL;

    /* Store video mimetypes */
    client->info.video_mimetypes = malloc(sizeof(char*) * (video->argc+1));
    memcpy(client->info.video_mimetypes, video->argv,
            sizeof(char*) * video->argc);
    client->info.video_mimetypes[video->argc] = NULL;

    /* Store client */
    if (guacd_client_map_add(map, client))
        guacd_log_error("Unable to add client. Internal client storage has failed");

    /* Send connection ID */
    guacd_log_info("Connection ID is \"%s\"", client->connection_id);
    guac_protocol_send_ready(socket, client->connection_id);

    /* Init client */
    init_result = guac_client_plugin_init_client(plugin,
                client, connect->argc, connect->argv);

    guac_instruction_free(connect);

    /* If client could not be started, free everything and fail */
    if (init_result) {

        guac_client_free(client);

        guacd_log_guac_error("Error instantiating client");

        if (guac_client_plugin_close(plugin))
            guacd_log_guac_error("Error closing client plugin");

        guac_socket_free(socket);
        return;
    }

    /* Start client threads */
    guacd_log_info("Starting client");
    if (guacd_client_start(client))
        guacd_log_error("Client finished abnormally");
    else
        guacd_log_info("Client finished normally");

    /* Remove client */
    if (guacd_client_map_remove(map, client->connection_id) == NULL)
        guacd_log_error("Unable to remove client. Internal client storage has failed");

    /* Free mimetype lists */
    free(client->info.audio_mimetypes);
    free(client->info.video_mimetypes);

    /* Free remaining instructions */
    guac_instruction_free(audio);
    guac_instruction_free(video);
    guac_instruction_free(size);

    /* Clean up */
    guac_client_free(client);
    if (guac_client_plugin_close(plugin))
        guacd_log_error("Error closing client plugin");

    /* Close socket */
    guac_socket_free(socket);

}
Example #4
0
void test_instruction_read() {

    int rfd, wfd;
    int fd[2], childpid;

    char test_string[] = "4.test,6.a" UTF8_4 "b,"
                         "5.12345,10.a" UTF8_8 "c;"
                         "5.test2,10.hellohello,15.worldworldworld;";

    /* Create pipe */
    CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);

    /* File descriptors */
    rfd = fd[0];
    wfd = fd[1];

    /* Fork */
    if ((childpid = fork()) == -1) {
        /* ERROR */
        perror("fork");
        return;
    }

    /* Child (pipe writer) */
    if (childpid != 0) {
        close(rfd);
        CU_ASSERT_EQUAL(
            write(wfd, test_string, sizeof(test_string)),
            sizeof(test_string)
        );
        exit(0);
    }

    /* Parent (unit test) */
    else {

        guac_socket* socket;
        guac_instruction* instruction;

        close(wfd);

        /* Open guac socket */
        socket = guac_socket_open(rfd);
        CU_ASSERT_PTR_NOT_NULL_FATAL(socket);

        /* Read instruction */
        instruction = guac_instruction_read(socket, 1000000);
        CU_ASSERT_PTR_NOT_NULL_FATAL(instruction);
        
        /* Validate contents */
        CU_ASSERT_STRING_EQUAL(instruction->opcode, "test");
        CU_ASSERT_EQUAL_FATAL(instruction->argc, 3);
        CU_ASSERT_STRING_EQUAL(instruction->argv[0], "a" UTF8_4 "b");
        CU_ASSERT_STRING_EQUAL(instruction->argv[1], "12345");
        CU_ASSERT_STRING_EQUAL(instruction->argv[2], "a" UTF8_8 "c");
        
        /* Read another instruction */
        guac_instruction_free(instruction);
        instruction = guac_instruction_read(socket, 1000000);

        /* Validate contents */
        CU_ASSERT_STRING_EQUAL(instruction->opcode, "test2");
        CU_ASSERT_EQUAL_FATAL(instruction->argc, 2);
        CU_ASSERT_STRING_EQUAL(instruction->argv[0], "hellohello");
        CU_ASSERT_STRING_EQUAL(instruction->argv[1], "worldworldworld");

        guac_instruction_free(instruction);
        guac_socket_free(socket);

    }
 
}