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;
}