static int guacd_route_connection()

in src/guacd/connection.c [238:362]


static int guacd_route_connection(guacd_proc_map* map, guac_socket* socket) {

    guac_parser* parser = guac_parser_alloc();

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

    /* Get protocol from select instruction */
    if (guac_parser_expect(parser, socket, GUACD_USEC_TIMEOUT, "select")) {

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

        guac_parser_free(parser);
        return 1;
    }

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

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

        guac_parser_free(parser);
        return 1;
    }

    guacd_proc* proc;
    int new_process;

    const char* identifier = parser->argv[0];

    /* If connection ID, retrieve existing process */
    if (identifier[0] == GUAC_CLIENT_ID_PREFIX) {

        proc = guacd_proc_map_retrieve(map, identifier);
        new_process = 0;

        /* Warn and ward off client if requested connection does not exist */
        if (proc == NULL) {
            guacd_log(GUAC_LOG_INFO, "Connection \"%s\" does not exist", identifier);
            guac_protocol_send_error(socket, "No such connection.",
                    GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
        }

        else
            guacd_log(GUAC_LOG_INFO, "Joining existing connection \"%s\"",
                    identifier);

    }

    /* Otherwise, create new client */
    else {

        guacd_log(GUAC_LOG_INFO, "Creating new client for protocol \"%s\"",
                identifier);

        /* Create new process */
        proc = guacd_create_proc(identifier);
        new_process = 1;

    }

    /* Abort if no process exists for the requested connection */
    if (proc == NULL) {
        guacd_log_guac_error(GUAC_LOG_INFO, "Connection did not succeed");
        guac_parser_free(parser);
        return 1;
    }

    /* Add new user (in the case of a new process, this will be the owner */
    int add_user_failed = guacd_add_user(proc, parser, socket);

    /* If new process was created, manage that process */
    if (new_process) {

        /* The new process will only be active if the user was added */
        if (!add_user_failed) {

            /* Log connection ID */
            guacd_log(GUAC_LOG_INFO, "Connection ID is \"%s\"",
                    proc->client->connection_id);

            /* Store process, allowing other users to join */
            guacd_proc_map_add(map, proc);

            /* Wait for child to finish */
            waitpid(proc->pid, NULL, 0);

            /* Remove client */
            if (guacd_proc_map_remove(map, proc->client->connection_id) == NULL)
                guacd_log(GUAC_LOG_ERROR, "Internal failure removing "
                        "client \"%s\". Client record will never be freed.",
                        proc->client->connection_id);
            else
                guacd_log(GUAC_LOG_INFO, "Connection \"%s\" removed.",
                        proc->client->connection_id);

        }

        /* Parser must be manually freed if the process did not start */
        else
            guac_parser_free(parser);

        /* Force process to stop and clean up */
        guacd_proc_stop(proc);

        /* Free skeleton client */
        guac_client_free(proc->client);

        /* Clean up */
        close(proc->fd_socket);
        free(proc);

    }

    /* Routing succeeded only if the user was added to a process */
    return add_user_failed;

}