int guac_client_init(guac_client* client, int argc, char** argv) { rfbClient* rfb_client; vnc_guac_client_data* guac_client_data; int retries_remaining; /* Set up libvncclient logging */ rfbClientLog = guac_vnc_client_log_info; rfbClientErr = guac_vnc_client_log_error; /*** PARSE ARGUMENTS ***/ if (argc != VNC_ARGS_COUNT) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Wrong argument count received."); return 1; } /* Alloc client data */ guac_client_data = malloc(sizeof(vnc_guac_client_data)); client->data = guac_client_data; guac_client_data->hostname = strdup(argv[IDX_HOSTNAME]); guac_client_data->port = atoi(argv[IDX_PORT]); guac_client_data->password = strdup(argv[IDX_PASSWORD]); /* NOTE: freed by libvncclient */ guac_client_data->default_surface = NULL; /* Set flags */ guac_client_data->remote_cursor = (strcmp(argv[IDX_CURSOR], "remote") == 0); guac_client_data->swap_red_blue = (strcmp(argv[IDX_SWAP_RED_BLUE], "true") == 0); guac_client_data->read_only = (strcmp(argv[IDX_READ_ONLY], "true") == 0); /* Parse color depth */ guac_client_data->color_depth = atoi(argv[IDX_COLOR_DEPTH]); #ifdef ENABLE_VNC_REPEATER /* Set repeater parameters if specified */ if (argv[IDX_DEST_HOST][0] != '\0') guac_client_data->dest_host = strdup(argv[IDX_DEST_HOST]); else guac_client_data->dest_host = NULL; if (argv[IDX_DEST_PORT][0] != '\0') guac_client_data->dest_port = atoi(argv[IDX_DEST_PORT]); #endif /* Set encodings if specified */ if (argv[IDX_ENCODINGS][0] != '\0') guac_client_data->encodings = strdup(argv[IDX_ENCODINGS]); else guac_client_data->encodings = NULL; /* Parse autoretry */ if (argv[IDX_AUTORETRY][0] != '\0') retries_remaining = atoi(argv[IDX_AUTORETRY]); else retries_remaining = 0; #ifdef ENABLE_VNC_LISTEN /* Set reverse-connection flag */ guac_client_data->reverse_connect = (strcmp(argv[IDX_REVERSE_CONNECT], "true") == 0); /* Parse listen timeout */ if (argv[IDX_LISTEN_TIMEOUT][0] != '\0') guac_client_data->listen_timeout = atoi(argv[IDX_LISTEN_TIMEOUT]); else guac_client_data->listen_timeout = 5000; #endif /* Init clipboard */ guac_client_data->clipboard = guac_common_clipboard_alloc(GUAC_VNC_CLIPBOARD_MAX_LENGTH); /* Configure clipboard encoding */ if (guac_vnc_set_clipboard_encoding(client, argv[IDX_CLIPBOARD_ENCODING])) guac_client_log(client, GUAC_LOG_INFO, "Using non-standard VNC clipboard encoding: '%s'.", argv[IDX_CLIPBOARD_ENCODING]); /* Ensure connection is kept alive during lengthy connects */ guac_socket_require_keep_alive(client->socket); /* Attempt connection */ rfb_client = __guac_vnc_get_client(client); /* If unsuccessful, retry as many times as specified */ while (!rfb_client && retries_remaining > 0) { struct timespec guac_vnc_connect_interval = { .tv_sec = GUAC_VNC_CONNECT_INTERVAL/1000, .tv_nsec = (GUAC_VNC_CONNECT_INTERVAL%1000)*1000000 }; guac_client_log(client, GUAC_LOG_INFO, "Connect failed. Waiting %ims before retrying...", GUAC_VNC_CONNECT_INTERVAL); /* Wait for given interval then retry */ nanosleep(&guac_vnc_connect_interval, NULL); rfb_client = __guac_vnc_get_client(client); retries_remaining--; } /* If the final connect attempt fails, return error */ if (!rfb_client) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to connect to VNC server."); return 1; } #ifdef ENABLE_PULSE guac_client_data->audio_enabled = (strcmp(argv[IDX_ENABLE_AUDIO], "true") == 0); /* If an encoding is available, load an audio stream */ if (guac_client_data->audio_enabled) { guac_client_data->audio = guac_audio_stream_alloc(client, NULL); /* Load servername if specified */ if (argv[IDX_AUDIO_SERVERNAME][0] != '\0') guac_client_data->pa_servername = strdup(argv[IDX_AUDIO_SERVERNAME]); else guac_client_data->pa_servername = NULL; /* If successful, init audio system */ if (guac_client_data->audio != NULL) { guac_client_log(client, GUAC_LOG_INFO, "Audio will be encoded as %s", guac_client_data->audio->encoder->mimetype); /* Require threadsafe sockets if audio enabled */ guac_socket_require_threadsafe(client->socket); /* Start audio stream */ guac_pa_start_stream(client); } /* Otherwise, audio loading failed */ else guac_client_log(client, GUAC_LOG_INFO, "No available audio encoding. Sound disabled."); } /* end if audio enabled */ #endif #ifdef ENABLE_COMMON_SSH guac_common_ssh_init(client); /* Connect via SSH if SFTP is enabled */ if (strcmp(argv[IDX_ENABLE_SFTP], "true") == 0) { guac_client_log(client, GUAC_LOG_DEBUG, "Connecting via SSH for SFTP filesystem access."); guac_client_data->sftp_user = guac_common_ssh_create_user(argv[IDX_SFTP_USERNAME]); /* Import private key, if given */ if (argv[IDX_SFTP_PRIVATE_KEY][0] != '\0') { guac_client_log(client, GUAC_LOG_DEBUG, "Authenticating with private key."); /* Abort if private key cannot be read */ if (guac_common_ssh_user_import_key(guac_client_data->sftp_user, argv[IDX_SFTP_PRIVATE_KEY], argv[IDX_SFTP_PASSPHRASE])) { guac_common_ssh_destroy_user(guac_client_data->sftp_user); return 1; } } /* Otherwise, use specified password */ else { guac_client_log(client, GUAC_LOG_DEBUG, "Authenticating with password."); guac_common_ssh_user_set_password(guac_client_data->sftp_user, argv[IDX_SFTP_PASSWORD]); } /* Parse hostname - use VNC hostname by default */ const char* sftp_hostname = argv[IDX_SFTP_HOSTNAME]; if (sftp_hostname[0] == '\0') sftp_hostname = guac_client_data->hostname; /* Parse port, defaulting to standard SSH port */ const char* sftp_port = argv[IDX_SFTP_PORT]; if (sftp_port[0] == '\0') sftp_port = "22"; /* Attempt SSH connection */ guac_client_data->sftp_session = guac_common_ssh_create_session(client, sftp_hostname, sftp_port, guac_client_data->sftp_user); /* Fail if SSH connection does not succeed */ if (guac_client_data->sftp_session == NULL) { /* Already aborted within guac_common_ssh_create_session() */ guac_common_ssh_destroy_user(guac_client_data->sftp_user); return 1; } /* Load and expose filesystem */ guac_client_data->sftp_filesystem = guac_common_ssh_create_sftp_filesystem( guac_client_data->sftp_session, "/"); /* Abort if SFTP connection fails */ if (guac_client_data->sftp_filesystem == NULL) { guac_common_ssh_destroy_session(guac_client_data->sftp_session); guac_common_ssh_destroy_user(guac_client_data->sftp_user); return 1; } /* Configure destination for basic uploads, if specified */ if (argv[IDX_SFTP_DIRECTORY][0] != '\0') guac_common_ssh_sftp_set_upload_path( guac_client_data->sftp_filesystem, argv[IDX_SFTP_DIRECTORY]); /* Set file handler for basic uploads */ client->file_handler = guac_vnc_sftp_file_handler; guac_client_log(client, GUAC_LOG_DEBUG, "SFTP connection succeeded."); } #endif /* Set remaining client data */ guac_client_data->rfb_client = rfb_client; guac_client_data->copy_rect_used = 0; guac_client_data->cursor = guac_client_alloc_buffer(client); /* Set handlers */ client->handle_messages = vnc_guac_client_handle_messages; client->free_handler = vnc_guac_client_free_handler; /* If not read-only, set input handlers and pointer */ if (guac_client_data->read_only == 0) { /* Only handle mouse/keyboard/clipboard if not read-only */ client->mouse_handler = vnc_guac_client_mouse_handler; client->key_handler = vnc_guac_client_key_handler; client->clipboard_handler = guac_vnc_clipboard_handler; /* If not read-only but cursor is remote, set a dot cursor */ if (guac_client_data->remote_cursor) guac_common_set_dot_cursor(client); /* Otherwise, set pointer until explicitly requested otherwise */ else guac_common_set_pointer_cursor(client); } /* Send name */ guac_protocol_send_name(client->socket, rfb_client->desktopName); /* Create default surface */ guac_client_data->default_surface = guac_common_surface_alloc(client->socket, GUAC_DEFAULT_LAYER, rfb_client->width, rfb_client->height); return 0; }
int guac_client_init(guac_client* client, int argc, char** argv) { rfbClient* rfb_client; vnc_guac_client_data* guac_client_data; int retries_remaining; /* Set up libvncclient logging */ rfbClientLog = guac_vnc_client_log_info; rfbClientErr = guac_vnc_client_log_error; /*** PARSE ARGUMENTS ***/ if (argc != VNC_ARGS_COUNT) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Wrong argument count received."); return 1; } /* Alloc client data */ guac_client_data = malloc(sizeof(vnc_guac_client_data)); client->data = guac_client_data; guac_client_data->hostname = strdup(argv[IDX_HOSTNAME]); guac_client_data->port = atoi(argv[IDX_PORT]); /* Set remote cursor flag */ guac_client_data->remote_cursor = (strcmp(argv[IDX_CURSOR], "remote") == 0); /* Set red/blue swap flag */ guac_client_data->swap_red_blue = (strcmp(argv[IDX_SWAP_RED_BLUE], "true") == 0); /* Set read-only flag */ guac_client_data->read_only = (strcmp(argv[IDX_READ_ONLY], "true") == 0); /* Freed after use by libvncclient */ guac_client_data->password = strdup(argv[IDX_PASSWORD]); /* Parse color depth */ guac_client_data->color_depth = atoi(argv[IDX_COLOR_DEPTH]); #ifdef ENABLE_VNC_REPEATER /* Set repeater parameters if specified */ if (argv[IDX_DEST_HOST][0] != '\0') guac_client_data->dest_host = strdup(argv[IDX_DEST_HOST]); else guac_client_data->dest_host = NULL; if (argv[IDX_DEST_PORT][0] != '\0') guac_client_data->dest_port = atoi(argv[IDX_DEST_PORT]); #endif /* Set encodings if specified */ if (argv[IDX_ENCODINGS][0] != '\0') guac_client_data->encodings = strdup(argv[IDX_ENCODINGS]); else guac_client_data->encodings = NULL; /* Parse autoretry */ if (argv[IDX_AUTORETRY][0] != '\0') retries_remaining = atoi(argv[IDX_AUTORETRY]); else retries_remaining = 0; #ifdef ENABLE_VNC_LISTEN /* Set reverse-connection flag */ guac_client_data->reverse_connect = (strcmp(argv[IDX_REVERSE_CONNECT], "true") == 0); /* Parse listen timeout */ if (argv[IDX_LISTEN_TIMEOUT][0] != '\0') guac_client_data->listen_timeout = atoi(argv[IDX_LISTEN_TIMEOUT]); else guac_client_data->listen_timeout = 5000; #endif /* Init clipboard */ guac_client_data->clipboard = guac_common_clipboard_alloc(GUAC_VNC_CLIPBOARD_MAX_LENGTH); /* Ensure connection is kept alive during lengthy connects */ guac_socket_require_keep_alive(client->socket); /* Attempt connection */ rfb_client = __guac_vnc_get_client(client); /* If unsuccessful, retry as many times as specified */ while (!rfb_client && retries_remaining > 0) { guac_client_log_info(client, "Connect failed. Waiting %ims before retrying...", GUAC_VNC_CONNECT_INTERVAL); /* Wait for given interval then retry */ usleep(GUAC_VNC_CONNECT_INTERVAL*1000); rfb_client = __guac_vnc_get_client(client); retries_remaining--; } /* If the final connect attempt fails, return error */ if (!rfb_client) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Unable to connect to VNC server."); return 1; } #ifdef ENABLE_PULSE guac_client_data->audio_enabled = (strcmp(argv[IDX_ENABLE_AUDIO], "true") == 0); /* If an encoding is available, load an audio stream */ if (guac_client_data->audio_enabled) { guac_client_data->audio = guac_audio_stream_alloc(client, NULL); /* Load servername if specified */ if (argv[IDX_AUDIO_SERVERNAME][0] != '\0') guac_client_data->pa_servername = strdup(argv[IDX_AUDIO_SERVERNAME]); else guac_client_data->pa_servername = NULL; /* If successful, init audio system */ if (guac_client_data->audio != NULL) { guac_client_log_info(client, "Audio will be encoded as %s", guac_client_data->audio->encoder->mimetype); /* Require threadsafe sockets if audio enabled */ guac_socket_require_threadsafe(client->socket); /* Start audio stream */ guac_pa_start_stream(client); } /* Otherwise, audio loading failed */ else guac_client_log_info(client, "No available audio encoding. Sound disabled."); } /* end if audio enabled */ #endif /* Set remaining client data */ guac_client_data->rfb_client = rfb_client; guac_client_data->copy_rect_used = 0; guac_client_data->cursor = guac_client_alloc_buffer(client); /* Set handlers */ client->handle_messages = vnc_guac_client_handle_messages; client->free_handler = vnc_guac_client_free_handler; /* If not read-only, set input handlers and pointer */ if (guac_client_data->read_only == 0) { /* Only handle mouse/keyboard/clipboard if not read-only */ client->mouse_handler = vnc_guac_client_mouse_handler; client->key_handler = vnc_guac_client_key_handler; client->clipboard_handler = vnc_guac_client_clipboard_handler; client->blob_handler = vnc_guac_client_blob_handler; client->end_handler = vnc_guac_client_end_handler; /* If not read-only but cursor is remote, set a dot cursor */ if (guac_client_data->remote_cursor) guac_common_set_dot_cursor(client); /* Otherwise, set pointer until explicitly requested otherwise */ else guac_common_set_pointer_cursor(client); } /* Send name */ guac_protocol_send_name(client->socket, rfb_client->desktopName); /* Send size */ guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, rfb_client->width, rfb_client->height); return 0; }
int guac_client_init(guac_client* client, int argc, char** argv) { rfbClient* rfb_client; vnc_guac_client_data* guac_client_data; int read_only; /* Set up libvncclient logging */ rfbClientLog = guac_vnc_client_log_info; rfbClientErr = guac_vnc_client_log_error; /*** PARSE ARGUMENTS ***/ if (argc != VNC_ARGS_COUNT) { guac_protocol_send_error(client->socket, "Wrong argument count received."); guac_socket_flush(client->socket); return 1; } /* Alloc client data */ guac_client_data = malloc(sizeof(vnc_guac_client_data)); client->data = guac_client_data; /* Set read-only flag */ read_only = (strcmp(argv[IDX_READ_ONLY], "true") == 0); /* Set red/blue swap flag */ guac_client_data->swap_red_blue = (strcmp(argv[IDX_SWAP_RED_BLUE], "true") == 0); /* Freed after use by libvncclient */ guac_client_data->password = strdup(argv[IDX_PASSWORD]); /*** INIT RFB CLIENT ***/ rfb_client = rfbGetClient(8, 3, 4); /* 32-bpp client */ /* Store Guac client in rfb client */ rfbClientSetClientData(rfb_client, __GUAC_CLIENT, client); /* Framebuffer update handler */ rfb_client->GotFrameBufferUpdate = guac_vnc_update; rfb_client->GotCopyRect = guac_vnc_copyrect; /* Do not handle clipboard and local cursor if read-only */ if (read_only == 0) { /* Enable client-side cursor */ rfb_client->GotCursorShape = guac_vnc_cursor; rfb_client->appData.useRemoteCursor = TRUE; /* Clipboard */ rfb_client->GotXCutText = guac_vnc_cut_text; } /* Password */ rfb_client->GetPassword = guac_vnc_get_password; /* Depth */ guac_vnc_set_pixel_format(rfb_client, atoi(argv[IDX_COLOR_DEPTH])); #ifdef ENABLE_PULSE guac_client_data->audio_enabled = (strcmp(argv[IDX_ENABLE_AUDIO], "true") == 0); /* If an encoding is available, load an audio stream */ if (guac_client_data->audio_enabled) { guac_client_data->audio = guac_audio_stream_alloc(client, NULL); /* Load servername if specified */ if (argv[IDX_AUDIO_SERVERNAME][0] != '\0') guac_client_data->pa_servername = strdup(argv[IDX_AUDIO_SERVERNAME]); else guac_client_data->pa_servername = NULL; /* If successful, init audio system */ if (guac_client_data->audio != NULL) { guac_client_log_info(client, "Audio will be encoded as %s", guac_client_data->audio->encoder->mimetype); /* Require threadsafe sockets if audio enabled */ guac_socket_require_threadsafe(client->socket); /* Start audio stream */ guac_pa_start_stream(client); } /* Otherwise, audio loading failed */ else guac_client_log_info(client, "No available audio encoding. Sound disabled."); } /* end if audio enabled */ #endif /* Hook into allocation so we can handle resize. */ guac_client_data->rfb_MallocFrameBuffer = rfb_client->MallocFrameBuffer; rfb_client->MallocFrameBuffer = guac_vnc_malloc_framebuffer; rfb_client->canHandleNewFBSize = 1; /* Set hostname and port */ rfb_client->serverHost = strdup(argv[0]); rfb_client->serverPort = atoi(argv[1]); #ifdef ENABLE_VNC_REPEATER /* Set repeater parameters if specified */ if(argv[IDX_DEST_HOST][0] != '\0') rfb_client->destHost = strdup(argv[IDX_DEST_HOST]); if(argv[IDX_DEST_PORT][0] != '\0') rfb_client->destPort = atoi(argv[IDX_DEST_PORT]); #endif /* Set encodings if specified */ if (argv[IDX_ENCODINGS][0] != '\0') rfb_client->appData.encodingsString = guac_client_data->encodings = strdup(argv[IDX_ENCODINGS]); else guac_client_data->encodings = NULL; /* Connect */ if (!rfbInitClient(rfb_client, NULL, NULL)) { guac_protocol_send_error(client->socket, "Error initializing VNC client"); guac_socket_flush(client->socket); return 1; } /* Set remaining client data */ guac_client_data->rfb_client = rfb_client; guac_client_data->copy_rect_used = 0; guac_client_data->cursor = guac_client_alloc_buffer(client); /* Set handlers */ client->handle_messages = vnc_guac_client_handle_messages; client->free_handler = vnc_guac_client_free_handler; if (read_only == 0) { /* Do not handle mouse/keyboard/clipboard if read-only */ client->mouse_handler = vnc_guac_client_mouse_handler; client->key_handler = vnc_guac_client_key_handler; client->clipboard_handler = vnc_guac_client_clipboard_handler; } /* Send name */ guac_protocol_send_name(client->socket, rfb_client->desktopName); /* Send size */ guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, rfb_client->width, rfb_client->height); return 0; }