/** * Loads all keysym/scancode mappings declared within the given keymap and its * parent keymap, if any. These mappings are stored within the given * guac_rdp_keyboard structure for future use in translating keysyms to the * scancodes required by RDP key events. * * @param keyboard * The guac_rdp_keyboard which should be initialized with the * keysym/scancode mapping defined in the given keymap. * * @param keymap * The keymap to use to populate the given client's keysym/scancode * mapping. */ static void __guac_rdp_keyboard_load_keymap(guac_rdp_keyboard* keyboard, const guac_rdp_keymap* keymap) { /* Get mapping */ const guac_rdp_keysym_desc* mapping = keymap->mapping; /* If parent exists, load parent first */ if (keymap->parent != NULL) __guac_rdp_keyboard_load_keymap(keyboard, keymap->parent); /* Log load */ guac_client_log(keyboard->client, GUAC_LOG_INFO, "Loading keymap \"%s\"", keymap->name); /* Load mapping into keymap */ while (mapping->keysym != 0) { /* Locate corresponding key definition within keyboard */ guac_rdp_key* key = guac_rdp_keyboard_map_key(keyboard, mapping->keysym); /* Copy mapping (if key is mappable) */ if (key != NULL) key->definition = mapping; else guac_client_log(keyboard->client, GUAC_LOG_DEBUG, "Ignoring unmappable keysym 0x%X", mapping->keysym); /* Next keysym */ mapping++; } }
int guac_rdp_svc_pipe_handler(guac_client* client, guac_stream* stream, char* mimetype, char* name) { guac_rdp_stream* rdp_stream; guac_rdp_svc* svc = guac_rdp_get_svc(client, name); /* Fail if no such SVC */ if (svc == NULL) { guac_client_log(client, GUAC_LOG_ERROR, "Requested non-existent pipe: \"%s\".", name); guac_protocol_send_ack(client->socket, stream, "FAIL (NO SUCH PIPE)", GUAC_PROTOCOL_STATUS_CLIENT_BAD_REQUEST); guac_socket_flush(client->socket); return 0; } else guac_client_log(client, GUAC_LOG_ERROR, "Inbound half of channel \"%s\" connected.", name); /* Init stream data */ stream->data = rdp_stream = malloc(sizeof(guac_rdp_stream)); stream->blob_handler = guac_rdp_svc_blob_handler; rdp_stream->type = GUAC_RDP_INBOUND_SVC_STREAM; rdp_stream->svc = svc; svc->input_pipe = stream; return 0; }
/** * Called periodically by guacd whenever the plugin should handle accumulated * data and render a frame. * * @param client * The guac_client associated with the plugin that should render a frame. * * @return * Non-zero if an error occurs, zero otherwise. */ static int streamtest_client_message_handler(guac_client* client) { /* Get stream state from client */ streamtest_state* state = (streamtest_state*) client->data; int frame_start; int frame_duration; /* Record start of frame */ frame_start = streamtest_utime(); /* Read from stream and write as blob(s) */ if (!state->paused) { /* Attempt to fill the available buffer space */ int length = streamtest_fill_buffer(state->fd, state->frame_buffer, state->frame_bytes); /* Abort connection if we cannot read */ if (length == -1) { guac_client_log(client, GUAC_LOG_ERROR, "Unable to read from specified file: %s", strerror(errno)); return 1; } /* Write all data read as blobs */ if (length > 0) streamtest_write_blobs(client->socket, state->stream, state->frame_buffer, length); /* Disconnect on EOF */ else { guac_client_log(client, GUAC_LOG_INFO, "Media streaming complete"); guac_client_stop(client); } } /* Update progress bar */ streamtest_render_progress(client); guac_socket_flush(client->socket); /* Sleep for remainder of frame */ frame_duration = streamtest_utime() - frame_start; if (frame_duration < state->frame_duration) streamtest_usleep(state->frame_duration - frame_duration); /* Warn (at debug level) if frame takes too long */ else guac_client_log(client, GUAC_LOG_DEBUG, "Frame took longer than requested duration: %i microseconds", frame_duration); /* Success */ return 0; }
int guac_telnet_user_key_handler(guac_user* user, int keysym, int pressed) { guac_client* client = user->client; guac_telnet_client* telnet_client = (guac_telnet_client*) client->data; guac_telnet_settings* settings = telnet_client->settings; guac_terminal* term = telnet_client->term; /* Skip if terminal not yet ready */ if (term == NULL) return 0; /* Stop searching for password */ if (settings->password_regex != NULL) { guac_client_log(client, GUAC_LOG_DEBUG, "Stopping password prompt search due to user input."); regfree(settings->password_regex); free(settings->password_regex); settings->password_regex = NULL; } /* Stop searching for username */ if (settings->username_regex != NULL) { guac_client_log(client, GUAC_LOG_DEBUG, "Stopping username prompt search due to user input."); regfree(settings->username_regex); free(settings->username_regex); settings->username_regex = NULL; } /* Intercept and handle Pause / Break / Ctrl+0 as "IAC BRK" */ if (pressed && ( keysym == 0xFF13 /* Pause */ || keysym == 0xFF6B /* Break */ || (term->mod_ctrl && keysym == '0') /* Ctrl + 0 */ )) { /* Send IAC BRK */ telnet_iac(telnet_client->telnet, TELNET_BREAK); return 0; } /* Send key */ guac_terminal_send_key(term, keysym, pressed); return 0; }
int guac_common_ssh_init(guac_client* client) { #ifdef LIBSSH2_USES_GCRYPT /* Init threadsafety in libgcrypt */ gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); if (!gcry_check_version(GCRYPT_VERSION)) { guac_client_log(client, GUAC_LOG_ERROR, "libgcrypt version mismatch."); return 1; } #endif /* Init threadsafety in OpenSSL */ guac_common_ssh_openssl_init_locks(CRYPTO_num_locks()); CRYPTO_set_id_callback(guac_common_ssh_openssl_id_callback); CRYPTO_set_locking_callback(guac_common_ssh_openssl_locking_callback); /* Init OpenSSL */ SSL_library_init(); ERR_load_crypto_strings(); /* Init libssh2 */ libssh2_init(0); /* Success */ return 0; }
void guac_rdp_bitmap_setsurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary) { guac_client* client = ((rdp_freerdp_context*) context)->client; rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data; if (primary) client_data->current_surface = client_data->default_surface; else { /* Make sure that the recieved bitmap is not NULL before processing */ if (bitmap == NULL) { guac_client_log(client, GUAC_LOG_INFO, "NULL bitmap found in bitmap_setsurface instruction."); return; } /* If not available as a surface, make available. */ if (((guac_rdp_bitmap*) bitmap)->surface == NULL) guac_rdp_cache_bitmap(context, bitmap); client_data->current_surface = ((guac_rdp_bitmap*) bitmap)->surface; } }
void guac_rdpdr_process_connect(rdpSvcPlugin* plugin) { /* Get RDPDR plugin */ guac_rdpdrPlugin* rdpdr = (guac_rdpdrPlugin*) plugin; /* Get client from plugin parameters */ guac_client* client = (guac_client*) plugin->channel_entry_points.pExtendedData; /* NULL out pExtendedData so we don't lose our guac_client due to an * automatic free() within libfreerdp */ plugin->channel_entry_points.pExtendedData = NULL; /* Get data from client */ rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data; /* Init plugin */ rdpdr->client = client; rdpdr->devices_registered = 0; /* Register printer if enabled */ if (client_data->settings.printing_enabled) guac_rdpdr_register_printer(rdpdr); /* Register drive if enabled */ if (client_data->settings.drive_enabled) guac_rdpdr_register_fs(rdpdr); /* Log that printing, etc. has been loaded */ guac_client_log(client, GUAC_LOG_INFO, "guacdr connected."); }
void guac_pa_start_stream(guac_client* client) { vnc_guac_client_data* client_data = (vnc_guac_client_data*) client->data; pa_context* context; guac_client_log(client, GUAC_LOG_INFO, "Starting audio stream"); guac_audio_stream_begin(client_data->audio, GUAC_VNC_AUDIO_RATE, GUAC_VNC_AUDIO_CHANNELS, GUAC_VNC_AUDIO_BPS); /* Init main loop */ client_data->pa_mainloop = pa_threaded_mainloop_new(); /* Create context */ context = pa_context_new( pa_threaded_mainloop_get_api(client_data->pa_mainloop), "Guacamole Audio"); /* Set up context */ pa_context_set_state_callback(context, __context_state_callback, client); pa_context_connect(context, client_data->pa_servername, PA_CONTEXT_NOAUTOSPAWN, NULL); /* Start loop */ pa_threaded_mainloop_start(client_data->pa_mainloop); }
int guac_client_init(guac_client* client) { /* Set client args */ client->args = GUAC_TELNET_CLIENT_ARGS; /* Allocate client instance data */ guac_telnet_client* telnet_client = calloc(1, sizeof(guac_telnet_client)); client->data = telnet_client; /* Init telnet client */ telnet_client->socket_fd = -1; telnet_client->naws_enabled = 0; telnet_client->echo_enabled = 1; /* Set handlers */ client->join_handler = guac_telnet_user_join_handler; client->free_handler = guac_telnet_client_free_handler; /* Set locale and warn if not UTF-8 */ setlocale(LC_CTYPE, ""); if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) { guac_client_log(client, GUAC_LOG_INFO, "Current locale does not use UTF-8. Some characters may " "not render correctly."); } /* Success */ return 0; }
void __guac_rdp_client_load_keymap(guac_client* client, const guac_rdp_keymap* keymap) { rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data; /* Get mapping */ const guac_rdp_keysym_desc* mapping = keymap->mapping; /* If parent exists, load parent first */ if (keymap->parent != NULL) __guac_rdp_client_load_keymap(client, keymap->parent); /* Log load */ guac_client_log(client, GUAC_LOG_INFO, "Loading keymap \"%s\"", keymap->name); /* Load mapping into keymap */ while (mapping->keysym != 0) { /* Copy mapping */ GUAC_RDP_KEYSYM_LOOKUP(guac_client_data->keymap, mapping->keysym) = *mapping; /* Next keysym */ mapping++; } }
void guac_rdpdr_process_print_job_close(guac_rdpdr_device* device, wStream* input_stream, int completion_id) { guac_rdpdr_printer_data* printer_data = (guac_rdpdr_printer_data*) device->data; wStream* output_stream = guac_rdpdr_new_io_completion(device, completion_id, STATUS_SUCCESS, 1); Stream_Write_UINT32(output_stream, 0); /* padding*/ /* Close input and wait for output thread to finish */ close(printer_data->printer_input); pthread_join(printer_data->printer_output_thread, NULL); /* Close file descriptors */ close(printer_data->printer_output); /* Close file */ guac_client_log(device->rdpdr->client, GUAC_LOG_INFO, "Print job closed"); guac_protocol_send_end(device->rdpdr->client->socket, printer_data->stream); svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream); }
static void guac_rdpdr_device_printer_iorequest_handler(guac_rdpdr_device* device, wStream* input_stream, int file_id, int completion_id, int major_func, int minor_func) { switch (major_func) { /* Print job create */ case IRP_MJ_CREATE: guac_rdpdr_process_print_job_create(device, input_stream, completion_id); break; /* Printer job write */ case IRP_MJ_WRITE: guac_rdpdr_process_print_job_write(device, input_stream, completion_id); break; /* Printer job close */ case IRP_MJ_CLOSE: guac_rdpdr_process_print_job_close(device, input_stream, completion_id); break; /* Log unknown */ default: guac_client_log(device->rdpdr->client, GUAC_LOG_ERROR, "Unknown printer I/O request function: 0x%x/0x%x", major_func, minor_func); } }
void guac_common_set_pointer_cursor(guac_user* user) { guac_client* client = user->client; guac_socket* socket = user->socket; /* Draw to buffer */ guac_layer* cursor = guac_client_alloc_buffer(client); cairo_surface_t* graphic = cairo_image_surface_create_for_data( guac_common_pointer_cursor, guac_common_pointer_cursor_format, guac_common_pointer_cursor_width, guac_common_pointer_cursor_height, guac_common_pointer_cursor_stride); guac_user_stream_png(user, socket, GUAC_COMP_SRC, cursor, 0, 0, graphic); cairo_surface_destroy(graphic); /* Set cursor */ guac_protocol_send_cursor(socket, 0, 0, cursor, 0, 0, guac_common_pointer_cursor_width, guac_common_pointer_cursor_height); /* Free buffer */ guac_client_free_buffer(client, cursor); guac_client_log(client, GUAC_LOG_DEBUG, "Client cursor image set to generic built-in pointer."); }
/** * Callback for the keyboard-interactive authentication method. Currently * supports just one prompt for the password. This callback is invoked as * needed to fullfill a call to libssh2_userauth_keyboard_interactive(). * * @param name * An arbitrary name which should be printed to the terminal for the * benefit of the user. This is currently ignored. * * @param name_len * The length of the name string, in bytes. * * @param instruction * Arbitrary instructions which should be printed to the terminal for the * benefit of the user. This is currently ignored. * * @param instruction_len * The length of the instruction string, in bytes. * * @param num_prompts * The number of keyboard-interactive prompts for which responses are * requested. This callback currently only supports one prompt, and assumes * that this prompt is requesting the password. * * @param prompts * An array of all keyboard-interactive prompts for which responses are * requested. * * @param responses * A parallel array into which all prompt responses should be stored. Each * entry within this array corresponds to the entry in the prompts array * with the same index. * * @param abstract * The value of the abstract parameter provided when the SSH session was * created with libssh2_session_init_ex(). */ static void guac_common_ssh_kbd_callback(const char *name, int name_len, const char *instruction, int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract) { guac_common_ssh_session* common_session = (guac_common_ssh_session*) *abstract; guac_client* client = common_session->client; /* Send password if only one prompt */ if (num_prompts == 1) { char* password = common_session->user->password; responses[0].text = strdup(password); responses[0].length = strlen(password); } /* If more than one prompt, a single password is not enough */ else guac_client_log(client, GUAC_LOG_WARNING, "Unsupported number of keyboard-interactive prompts: %i", num_prompts); }
void guac_rdpdr_fs_process_file_info(guac_rdpdr_device* device, wStream* input_stream, int file_id, int completion_id) { int fs_information_class; Stream_Read_UINT32(input_stream, fs_information_class); /* Dispatch to appropriate class-specific handler */ switch (fs_information_class) { case FileBasicInformation: guac_rdpdr_fs_process_query_basic_info(device, input_stream, file_id, completion_id); break; case FileStandardInformation: guac_rdpdr_fs_process_query_standard_info(device, input_stream, file_id, completion_id); break; case FileAttributeTagInformation: guac_rdpdr_fs_process_query_attribute_tag_info(device, input_stream, file_id, completion_id); break; default: guac_client_log(device->rdpdr->client, GUAC_LOG_INFO, "Unknown file information class: 0x%x", fs_information_class); } }
void guac_rdpdr_fs_process_close(guac_rdpdr_device* device, wStream* input_stream, int file_id, int completion_id) { wStream* output_stream; guac_rdp_fs_file* file; guac_client_log(device->rdpdr->client, GUAC_LOG_DEBUG, "%s: [file_id=%i]", __func__, file_id); /* Get file */ file = guac_rdp_fs_get_file((guac_rdp_fs*) device->data, file_id); if (file == NULL) return; /* If file was written to, and it's in the \Download folder, start stream */ if (file->bytes_written > 0 && strncmp(file->absolute_path, "\\Download\\", 10) == 0) { guac_rdpdr_start_download(device, file->absolute_path); guac_rdp_fs_delete((guac_rdp_fs*) device->data, file_id); } /* Close file */ guac_rdp_fs_close((guac_rdp_fs*) device->data, file_id); output_stream = guac_rdpdr_new_io_completion(device, completion_id, STATUS_SUCCESS, 4); Stream_Write(output_stream, "\0\0\0\0", 4); /* Padding */ svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream); }
void guac_rdpdr_fs_process_notify_change_directory(guac_rdpdr_device* device, wStream* input_stream, int file_id, int completion_id) { guac_client_log(device->rdpdr->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] Not implemented", __func__, file_id); }
guac_transfer_function guac_rdp_rop3_transfer_function(guac_client* client, int rop3) { /* Translate supported ROP3 opcodes into composite modes */ switch (rop3) { /* "DSon" !(src | dest) */ case 0x11: return GUAC_TRANSFER_BINARY_NOR; /* "DSna" !src & dest */ case 0x22: return GUAC_TRANSFER_BINARY_NSRC_AND; /* "Sn" !src */ case 0x33: return GUAC_TRANSFER_BINARY_NSRC; /* "SDna" (src & !dest) */ case 0x44: return GUAC_TRANSFER_BINARY_NDEST_AND; /* "Dn" !dest */ case 0x55: return GUAC_TRANSFER_BINARY_NDEST; /* "SRCINVERT" (src ^ dest) */ case 0x66: return GUAC_TRANSFER_BINARY_XOR; /* "DSan" !(src & dest) */ case 0x77: return GUAC_TRANSFER_BINARY_NAND; /* "SRCAND" (src & dest) */ case 0x88: return GUAC_TRANSFER_BINARY_AND; /* "DSxn" !(src ^ dest) */ case 0x99: return GUAC_TRANSFER_BINARY_XNOR; /* "MERGEPAINT" (!src | dest)*/ case 0xBB: return GUAC_TRANSFER_BINARY_NSRC_OR; /* "SDno" (src | !dest) */ case 0xDD: return GUAC_TRANSFER_BINARY_NDEST_OR; /* "SRCPAINT" (src | dest) */ case 0xEE: return GUAC_TRANSFER_BINARY_OR; /* 0x00 = "BLACKNESS" (0) */ /* 0xAA = "NOP" (dest) */ /* 0xCC = "SRCCOPY" (src) */ /* 0xFF = "WHITENESS" (1) */ } /* Log warning if ROP3 opcode not supported */ guac_client_log(client, GUAC_LOG_INFO, "guac_rdp_rop3_transfer_function: " "UNSUPPORTED opcode = 0x%02X", rop3); /* Default to BINARY_SRC */ return GUAC_TRANSFER_BINARY_SRC; }
int guac_rdp_download_ack_handler(guac_client* client, guac_stream* stream, char* message, guac_protocol_status status) { guac_rdp_stream* rdp_stream = (guac_rdp_stream*) stream->data; /* Get filesystem, return error if no filesystem */ guac_rdp_fs* fs = ((rdp_guac_client_data*) client->data)->filesystem; if (fs == NULL) { guac_protocol_send_ack(client->socket, stream, "FAIL (NO FS)", GUAC_PROTOCOL_STATUS_SERVER_ERROR); guac_socket_flush(client->socket); return 0; } /* If successful, read data */ if (status == GUAC_PROTOCOL_STATUS_SUCCESS) { /* Attempt read into buffer */ char buffer[4096]; int bytes_read = guac_rdp_fs_read(fs, rdp_stream->download_status.file_id, rdp_stream->download_status.offset, buffer, sizeof(buffer)); /* If bytes read, send as blob */ if (bytes_read > 0) { rdp_stream->download_status.offset += bytes_read; guac_protocol_send_blob(client->socket, stream, buffer, bytes_read); } /* If EOF, send end */ else if (bytes_read == 0) { guac_protocol_send_end(client->socket, stream); guac_client_free_stream(client, stream); free(rdp_stream); } /* Otherwise, fail stream */ else { guac_client_log(client, GUAC_LOG_ERROR, "Error reading file for download"); guac_protocol_send_end(client->socket, stream); guac_client_free_stream(client, stream); free(rdp_stream); } guac_socket_flush(client->socket); } /* Otherwise, return stream to client */ else guac_client_free_stream(client, stream); return 0; }
/** * Callback invoked by FreeRDP when the SSL/TLS certificate of the RDP server * needs to be verified. If this ever happens, this function implementation * will always fail unless the connection has been configured to ignore * certificate validity. * * @param instance * The FreeRDP instance associated with the RDP session whose SSL/TLS * certificate needs to be verified. * * @param subject * The subject to whom the certificate was issued. * * @param issuer * The authority that issued the certificate, * * @param fingerprint * The cryptographic fingerprint of the certificate. * * @return * TRUE if the certificate passes verification, FALSE otherwise. */ static BOOL rdp_freerdp_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) { rdpContext* context = instance->context; guac_client* client = ((rdp_freerdp_context*) context)->client; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; /* Bypass validation if ignore_certificate given */ if (rdp_client->settings->ignore_certificate) { guac_client_log(client, GUAC_LOG_INFO, "Certificate validation bypassed"); return TRUE; } guac_client_log(client, GUAC_LOG_INFO, "Certificate validation failed"); return FALSE; }
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; }
void guac_pa_stop_stream(guac_client* client) { vnc_guac_client_data* client_data = (vnc_guac_client_data*) client->data; /* Stop loop */ pa_threaded_mainloop_stop(client_data->pa_mainloop); guac_client_log(client, GUAC_LOG_INFO, "Audio stream finished"); }
static void __context_get_server_info_callback(pa_context* context, const pa_server_info* info, void* data) { guac_client* client = (guac_client*) data; /* If no default sink, cannot continue */ if (info->default_sink_name == NULL) { guac_client_log(client, GUAC_LOG_ERROR, "No default sink. Cannot stream audio."); return; } guac_client_log(client, GUAC_LOG_INFO, "Will use default sink: \"%s\"", info->default_sink_name); /* Wait for default sink information */ pa_operation_unref( pa_context_get_sink_info_by_name(context, info->default_sink_name, __context_get_sink_info_callback, client)); }
/** * Callback invoked by FreeRDP when authentication is required but a username * and password has not already been given. In the case of Guacamole, this * function always succeeds but does not populate the usename or password. The * username/password must be given within the connection parameters. * * @param instance * The FreeRDP instance associated with the RDP session requesting * credentials. * * @param username * Pointer to a string which will receive the user's username. * * @param password * Pointer to a string which will receive the user's password. * * @param domain * Pointer to a string which will receive the domain associated with the * user's account. * * @return * Always TRUE. */ static BOOL rdp_freerdp_authenticate(freerdp* instance, char** username, char** password, char** domain) { rdpContext* context = instance->context; guac_client* client = ((rdp_freerdp_context*) context)->client; /* Warn if connection is likely to fail due to lack of credentials */ guac_client_log(client, GUAC_LOG_INFO, "Authentication requested but username or password not given"); return TRUE; }
static void __stream_state_callback(pa_stream* stream, void* data) { guac_client* client = (guac_client*) data; switch (pa_stream_get_state(stream)) { case PA_STREAM_UNCONNECTED: guac_client_log(client, GUAC_LOG_INFO, "PulseAudio stream currently unconnected"); break; case PA_STREAM_CREATING: guac_client_log(client, GUAC_LOG_INFO, "PulseAudio stream being created..."); break; case PA_STREAM_READY: guac_client_log(client, GUAC_LOG_INFO, "PulseAudio stream now ready"); break; case PA_STREAM_FAILED: guac_client_log(client, GUAC_LOG_INFO, "PulseAudio stream connection failed"); break; case PA_STREAM_TERMINATED: guac_client_log(client, GUAC_LOG_INFO, "PulseAudio stream terminated"); break; default: guac_client_log(client, GUAC_LOG_INFO, "Unknown PulseAudio stream state: 0x%x", pa_stream_get_state(stream)); } }
void guac_rdpdr_fs_process_set_volume_info(guac_rdpdr_device* device, wStream* input_stream, int file_id, int completion_id) { wStream* output_stream = guac_rdpdr_new_io_completion(device, completion_id, STATUS_NOT_SUPPORTED, 0); guac_client_log(device->rdpdr->client, GUAC_LOG_DEBUG, "%s: [file_id=%i] Set volume info not supported", __func__, file_id); svc_plugin_send((rdpSvcPlugin*) device->rdpdr, output_stream); }
static int __guac_receive_channel_data(freerdp* rdp_inst, UINT16 channelId, BYTE* data, int size, int flags, int total_size) { #else static int __guac_receive_channel_data(freerdp* rdp_inst, int channelId, UINT8* data, int size, int flags, int total_size) { #endif return freerdp_channels_data(rdp_inst, channelId, data, size, flags, total_size); } #ifdef HAVE_FREERDP_EVENT_PUBSUB /** * Called whenever a channel connects via the PubSub event system within * FreeRDP. * * @param context * The rdpContext associated with the active RDP session. * * @param e * Event-specific arguments, mainly the name of the channel, and a * reference to the associated plugin loaded for that channel by FreeRDP. */ static void guac_rdp_channel_connected(rdpContext* context, ChannelConnectedEventArgs* e) { guac_client* client = ((rdp_freerdp_context*) context)->client; guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_settings* settings = rdp_client->settings; if (settings->resize_method == GUAC_RESIZE_DISPLAY_UPDATE) { #ifdef HAVE_RDPSETTINGS_SUPPORTDISPLAYCONTROL /* Store reference to the display update plugin once it's connected */ if (strcmp(e->name, DISP_DVC_CHANNEL_NAME) == 0) { DispClientContext* disp = (DispClientContext*) e->pInterface; /* Init module with current display size */ guac_rdp_disp_set_size(rdp_client->disp, rdp_client->settings, context->instance, guac_rdp_get_width(context->instance), guac_rdp_get_height(context->instance)); /* Store connected channel */ guac_rdp_disp_connect(rdp_client->disp, disp); guac_client_log(client, GUAC_LOG_DEBUG, "Display update channel connected."); } #endif } }
void guac_svc_process_terminate(rdpSvcPlugin* plugin) { /* Get corresponding guac_rdp_svc */ guac_svcPlugin* svc_plugin = (guac_svcPlugin*) plugin; guac_rdp_svc* svc = svc_plugin->svc; /* Remove and free SVC */ guac_client_log(svc->client, GUAC_LOG_INFO, "Closing channel \"%s\"...", svc->name); guac_rdp_remove_svc(svc->client, svc->name); free(svc); free(plugin); }
void guac_rdpdr_process_terminate(rdpSvcPlugin* plugin) { guac_rdpdrPlugin* rdpdr = (guac_rdpdrPlugin*) plugin; int i; for (i=0; i<rdpdr->devices_registered; i++) { guac_rdpdr_device* device = &(rdpdr->devices[i]); guac_client_log(rdpdr->client, GUAC_LOG_INFO, "Unloading device %i (%s)", device->device_id, device->device_name); device->free_handler(device); } free(plugin); }
void guac_rdpdr_start_download(guac_rdpdr_device* device, const char* path) { /* Get client and stream */ guac_client* client = device->rdpdr->client; int file_id = guac_rdp_fs_open((guac_rdp_fs*) device->data, path, ACCESS_FILE_READ_DATA, 0, DISP_FILE_OPEN, 0); /* If file opened successfully, start stream */ if (file_id >= 0) { guac_rdp_stream* rdp_stream; const char* basename; int i; char c; /* Associate stream with transfer status */ guac_stream* stream = guac_client_alloc_stream(client); stream->data = rdp_stream = malloc(sizeof(guac_rdp_stream)); stream->ack_handler = guac_rdp_download_ack_handler; rdp_stream->type = GUAC_RDP_DOWNLOAD_STREAM; rdp_stream->download_status.file_id = file_id; rdp_stream->download_status.offset = 0; /* Get basename from absolute path */ i=0; basename = path; do { c = path[i]; if (c == '/' || c == '\\') basename = &(path[i+1]); i++; } while (c != '\0'); GUAC_RDP_DEBUG(2, "Initiating download of \"%s\"", path); /* Begin stream */ guac_protocol_send_file(client->socket, stream, "application/octet-stream", basename); guac_socket_flush(client->socket); } else guac_client_log(client, GUAC_LOG_ERROR, "Unable to download \"%s\"", path); }