int rdp_guac_client_free_handler(guac_client* client) { rdp_guac_client_data* guac_client_data = (rdp_guac_client_data*) client->data; freerdp* rdp_inst = guac_client_data->rdp_inst; rdpChannels* channels = rdp_inst->context->channels; /* Clean up RDP client */ freerdp_channels_close(channels, rdp_inst); freerdp_channels_free(channels); freerdp_disconnect(rdp_inst); freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv); cache_free(rdp_inst->context->cache); freerdp_free(rdp_inst); /* Clean up filesystem, if allocated */ if (guac_client_data->filesystem != NULL) guac_rdp_fs_free(guac_client_data->filesystem); /* Free SVC list */ guac_common_list_free(guac_client_data->available_svc); /* Free client data */ guac_common_clipboard_free(guac_client_data->clipboard); guac_common_surface_free(guac_client_data->default_surface); free(guac_client_data); return 0; }
void test_channels(void) { rdpChannels* chan_man; rdpSettings settings = { 0 }; freerdp instance = { 0 }; RDP_EVENT* event; settings.hostname = "testhost"; instance.settings = &settings; instance.SendChannelData = test_rdp_channel_data; chan_man = freerdp_channels_new(); freerdp_channels_load_plugin(chan_man, &settings, "../channels/rdpdbg/rdpdbg.so", NULL); freerdp_channels_pre_connect(chan_man, &instance); freerdp_channels_post_connect(chan_man, &instance); freerdp_channels_data(&instance, 0, "testdata", 8, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, 8); freerdp_channels_data(&instance, 0, "testdata1", 9, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, 9); freerdp_channels_data(&instance, 0, "testdata11", 10, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, 10); freerdp_channels_data(&instance, 0, "testdata111", 11, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, 11); event = freerdp_event_new(RDP_EVENT_CLASS_DEBUG, 0, NULL, NULL); freerdp_channels_send_event(chan_man, event); while ((event = freerdp_channels_pop_event(chan_man)) == NULL) { freerdp_channels_check_fds(chan_man, &instance); } printf("responded event_type %d\n", event->event_type); freerdp_event_free(event); freerdp_channels_close(chan_man, &instance); freerdp_channels_free(chan_man); }
void wf_context_free(freerdp* instance, rdpContext* context) { if (context->cache) cache_free(context->cache); freerdp_channels_free(context->channels); }
rdpChannels* freerdp_channels_new(freerdp* instance) { rdpChannels* channels; channels = (rdpChannels*) calloc(1, sizeof(rdpChannels)); if (!channels) return NULL; if (!InitializeCriticalSectionAndSpinCount(&channels->channelsLock, 4000)) goto error; channels->instance = instance; channels->queue = MessageQueue_New(NULL); if (!channels->queue) goto error; channels->openHandles = HashTable_New(TRUE); if (!channels->openHandles) goto error; return channels; error: freerdp_channels_free(channels); return NULL; }
void test_drdynvc(void) { rdpChannels* chan_man; rdpSettings settings = { 0 }; freerdp instance = { 0 }; settings.Hostname = "testhost"; instance.settings = &settings; instance.SendChannelData = test_rdp_channel_data; chan_man = freerdp_channels_new(); freerdp_channels_load_plugin(chan_man, &settings, "../channels/drdynvc/drdynvc.so", NULL); freerdp_channels_pre_connect(chan_man, &instance); freerdp_channels_post_connect(chan_man, &instance); /* server sends capability request PDU */ freerdp_channels_data(&instance, 0, (char*)test_capability_request_data, sizeof(test_capability_request_data) - 1, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_capability_request_data) - 1); /* drdynvc sends capability response PDU to server */ data_received = 0; while (!data_received) { freerdp_channels_check_fds(chan_man, &instance); } freerdp_channels_close(chan_man, &instance); freerdp_channels_free(chan_man); }
static gboolean remmina_rdp_close_connection(RemminaProtocolWidget* gp) { rfContext* rfi; freerdp* instance; rfi = GET_DATA(gp); instance = rfi->instance; if (rfi->thread) { pthread_cancel(rfi->thread); if (rfi->thread) pthread_join(rfi->thread, NULL); } pthread_mutex_destroy(&rfi->mutex); g_mutex_free(rfi->gmutex); g_cond_free(rfi->gcond); remmina_rdp_event_uninit(gp); remmina_plugin_service->protocol_plugin_emit_signal(gp, "disconnect"); if (instance) { if ( rfi->connected ) { if (instance->context->channels) freerdp_channels_close(instance->context->channels, instance); freerdp_disconnect(instance); rfi->connected = False; } } if (rfi->rfx_context) { rfx_context_free(rfi->rfx_context); rfi->rfx_context = NULL; } if (instance) { /* Remove instance->context from gp object data to avoid double free */ g_object_steal_data(G_OBJECT(gp), "plugin-data"); if (instance->context->channels) { freerdp_channels_free(instance->context->channels); instance->context->channels = NULL; } freerdp_context_free(instance); /* context is rfContext* rfi */ freerdp_free(instance); rfi->instance = NULL; } return FALSE; }
static void wl_context_free(freerdp* instance, rdpContext* context) { if (context && context->channels) { freerdp_channels_close(context->channels, instance); freerdp_channels_free(context->channels); context->channels = NULL; } }
int freerdp_channels_global_uninit(void) { while (g_channels_list) freerdp_channels_free(g_channels_list->channels); freerdp_mutex_free(g_mutex_init); freerdp_mutex_free(g_mutex_list); return 0; }
static void android_context_free(freerdp* instance, rdpContext* context) { if (context && context->channels) { freerdp_channels_close(context->channels, instance); freerdp_channels_free(context->channels); context->channels = NULL; } android_event_queue_uninit(instance); }
static BOOL android_context_new(freerdp* instance, rdpContext* context) { if (!(context->channels = freerdp_channels_new())) return FALSE; if (!android_event_queue_init(instance)) { freerdp_channels_free(context->channels); return FALSE; } return TRUE; }
static gboolean remmina_rdp_close_connection(RemminaProtocolWidget* gp) { rfContext* rfi; freerdp* instance; rfi = GET_DATA(gp); instance = rfi->instance; if (rfi->thread) { pthread_cancel(rfi->thread); if (rfi->thread) pthread_join(rfi->thread, NULL); } pthread_mutex_destroy(&rfi->mutex); g_mutex_free(rfi->gmutex); g_cond_free(rfi->gcond); remmina_rdp_event_uninit(gp); remmina_plugin_service->protocol_plugin_emit_signal(gp, "disconnect"); if (instance) { if (rfi->channels) { //freerdp_channels_close(rfi->channels, instance); freerdp_channels_free(rfi->channels); rfi->channels = NULL; } if (freerdp_shall_disconnect(instance)) { freerdp_disconnect(instance); } } if (rfi->rfx_context) { rfx_context_free(rfi->rfx_context); rfi->rfx_context = NULL; } if (instance) { //freerdp_context_free(instance); /* context is rfContext* rfi */ freerdp_free(instance); } return FALSE; }
void wfreerdp_client_free(freerdp* instance, rdpContext* context) { if (!context) return; if (context->channels) { freerdp_channels_close(context->channels, instance); freerdp_channels_free(context->channels); context->channels = NULL; } if (context->cache) { cache_free(context->cache); context->cache = NULL; } }
/** Deallocator function for a rdp context. * The function will deallocate the resources from the 'instance' parameter that were allocated from a call * to freerdp_context_new(). * If the ContextFree callback is set in the 'instance' parameter, it will be called before deallocation occurs. * * @param instance - Pointer to the rdp_freerdp structure that was initialized by a call to freerdp_context_new(). * On return, the fields associated to the context are invalid. */ void freerdp_context_free(freerdp* instance) { if (!instance) return; if (!instance->context) return; IFCALL(instance->ContextFree, instance, instance->context); rdp_free(instance->context->rdp); instance->context->rdp = NULL; graphics_free(instance->context->graphics); instance->context->graphics = NULL; PubSub_Free(instance->context->pubSub); metrics_free(instance->context->metrics); CloseHandle(instance->context->channelErrorEvent); free(instance->context->errorDescription); CloseHandle(instance->context->abortEvent); instance->context->abortEvent = NULL; freerdp_channels_free(instance->context->channels); free(instance->context); instance->context = NULL; }
void test_cliprdr(void) { int i; rdpChannels* channels; rdpSettings settings = { 0 }; freerdp instance = { 0 }; RDP_EVENT* event; RDP_CB_FORMAT_LIST_EVENT* format_list_event; RDP_CB_DATA_REQUEST_EVENT* data_request_event; RDP_CB_DATA_RESPONSE_EVENT* data_response_event; settings.hostname = "testhost"; instance.settings = &settings; instance.SendChannelData = test_rdp_channel_data; channels = freerdp_channels_new(); freerdp_channels_load_plugin(channels, &settings, "../channels/cliprdr/cliprdr.so", NULL); freerdp_channels_pre_connect(channels, &instance); freerdp_channels_post_connect(channels, &instance); /* server sends cliprdr capabilities and monitor ready PDU */ freerdp_channels_data(&instance, 0, (char*)test_clip_caps_data, sizeof(test_clip_caps_data) - 1, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_clip_caps_data) - 1); freerdp_channels_data(&instance, 0, (char*)test_monitor_ready_data, sizeof(test_monitor_ready_data) - 1, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_monitor_ready_data) - 1); /* cliprdr sends clipboard_sync event to UI */ while ((event = freerdp_channels_pop_event(channels)) == NULL) { freerdp_channels_check_fds(channels, &instance); } printf("Got event %d\n", event->event_type); CU_ASSERT(event->event_type == RDP_EVENT_TYPE_CB_MONITOR_READY); freerdp_event_free(event); /* UI sends format_list event to cliprdr */ event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_FORMAT_LIST, event_process_callback, NULL); format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event; format_list_event->num_formats = 2; format_list_event->formats = (uint32*) xmalloc(sizeof(uint32) * 2); format_list_event->formats[0] = CB_FORMAT_TEXT; format_list_event->formats[1] = CB_FORMAT_HTML; event_processed = 0; freerdp_channels_send_event(channels, event); /* cliprdr sends format list PDU to server */ while (!event_processed) { freerdp_channels_check_fds(channels, &instance); } /* server sends format list response PDU to cliprdr */ freerdp_channels_data(&instance, 0, (char*)test_format_list_response_data, sizeof(test_format_list_response_data) - 1, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_format_list_response_data) - 1); /* server sends format list PDU to cliprdr */ freerdp_channels_data(&instance, 0, (char*)test_format_list_data, sizeof(test_format_list_data) - 1, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_format_list_data) - 1); /* cliprdr sends format_list event to UI */ while ((event = freerdp_channels_pop_event(channels)) == NULL) { freerdp_channels_check_fds(channels, &instance); } printf("Got event %d\n", event->event_type); CU_ASSERT(event->event_type == RDP_EVENT_TYPE_CB_FORMAT_LIST); if (event->event_type == RDP_EVENT_TYPE_CB_FORMAT_LIST) { format_list_event = (RDP_CB_FORMAT_LIST_EVENT*)event; for (i = 0; i < format_list_event->num_formats; i++) printf("Format: 0x%X\n", format_list_event->formats[i]); } freerdp_event_free(event); /* server sends data request PDU to cliprdr */ freerdp_channels_data(&instance, 0, (char*)test_data_request_data, sizeof(test_data_request_data) - 1, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_data_request_data) - 1); /* cliprdr sends data request event to UI */ while ((event = freerdp_channels_pop_event(channels)) == NULL) { freerdp_channels_check_fds(channels, &instance); } printf("Got event %d\n", event->event_type); CU_ASSERT(event->event_type == RDP_EVENT_TYPE_CB_DATA_REQUEST); if (event->event_type == RDP_EVENT_TYPE_CB_DATA_REQUEST) { data_request_event = (RDP_CB_DATA_REQUEST_EVENT*)event; printf("Requested format: 0x%X\n", data_request_event->format); } freerdp_event_free(event); /* UI sends data response event to cliprdr */ event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_DATA_RESPONSE, event_process_callback, NULL); data_response_event = (RDP_CB_DATA_RESPONSE_EVENT*)event; data_response_event->data = (uint8*)xmalloc(6); strcpy((char*)data_response_event->data, "hello"); data_response_event->size = 6; event_processed = 0; freerdp_channels_send_event(channels, event); /* cliprdr sends data response PDU to server */ while (!event_processed) { freerdp_channels_check_fds(channels, &instance); } /* UI sends data request event to cliprdr */ event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_DATA_REQUEST, event_process_callback, NULL); data_request_event = (RDP_CB_DATA_REQUEST_EVENT*)event; data_request_event->format = CB_FORMAT_UNICODETEXT; event_processed = 0; freerdp_channels_send_event(channels, event); /* cliprdr sends data request PDU to server */ while (!event_processed) { freerdp_channels_check_fds(channels, &instance); } /* server sends data response PDU to cliprdr */ freerdp_channels_data(&instance, 0, (char*)test_data_response_data, sizeof(test_data_response_data) - 1, CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST, sizeof(test_data_response_data) - 1); /* cliprdr sends data response event to UI */ while ((event = freerdp_channels_pop_event(channels)) == NULL) { freerdp_channels_check_fds(channels, &instance); } printf("Got event %d\n", event->event_type); CU_ASSERT(event->event_type == RDP_EVENT_TYPE_CB_DATA_RESPONSE); if (event->event_type == RDP_EVENT_TYPE_CB_DATA_RESPONSE) { data_response_event = (RDP_CB_DATA_RESPONSE_EVENT*)event; printf("Data response size: %d\n", data_response_event->size); freerdp_hexdump(data_response_event->data, data_response_event->size); } freerdp_event_free(event); freerdp_channels_close(channels, &instance); freerdp_channels_free(channels); }
int wlfreerdp_run(freerdp* instance) { int i; int fds; int max_fds; int rcount; int wcount; void* rfds[32]; void* wfds[32]; fd_set rfds_set; fd_set wfds_set; ZeroMemory(rfds, sizeof(rfds)); ZeroMemory(wfds, sizeof(wfds)); freerdp_connect(instance); while (1) { rcount = 0; wcount = 0; if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { printf("Failed to get FreeRDP file descriptor"); break; } if (freerdp_channels_get_fds(instance->context->channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) { printf("Failed to get FreeRDP file descriptor"); break; } max_fds = 0; FD_ZERO(&rfds_set); FD_ZERO(&wfds_set); for (i = 0; i < rcount; i++) { fds = (int)(long)(rfds[i]); if (fds > max_fds) max_fds = fds; FD_SET(fds, &rfds_set); } if (max_fds == 0) break; if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1) { if (!((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EINTR))) { printf("wlfreerdp_run: select failed\n"); break; } } if (freerdp_check_fds(instance) != TRUE) { printf("Failed to check FreeRDP file descriptor\n"); break; } if (freerdp_channels_check_fds(instance->context->channels, instance) != TRUE) { printf("Failed to check channel manager file descriptor\n"); break; } } struct display* display; struct window* window; struct wl_context* context; context = (struct wl_context*) instance->context; display = context->display; window = context->window; free(window->buffers[0].shm_data); free(window->buffers[1].shm_data); free(window->data); wl_buffer_destroy(window->buffers[0].buffer); wl_buffer_destroy(window->buffers[1].buffer); wl_shell_surface_destroy(window->shell_surface); wl_surface_destroy(window->surface); wl_shm_destroy(display->shm); wl_shell_destroy(display->shell); wl_compositor_destroy(display->compositor); wl_registry_destroy(display->registry); wl_display_disconnect(display->display); freerdp_channels_close(instance->context->channels, instance); freerdp_channels_free(instance->context->channels); freerdp_free(instance); return 0; }
/** * Waits for messages from the RDP server for the given number of microseconds. * * @param client * The client associated with the current RDP session. * * @param timeout_usecs * The maximum amount of time to wait, in microseconds. * * @return * A positive value if messages are ready, zero if the specified timeout * period elapsed, or a negative value if an error occurs. */ static int rdp_guac_client_wait_for_messages(guac_client* client, int timeout_usecs) { guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; freerdp* rdp_inst = rdp_client->rdp_inst; rdpChannels* channels = rdp_inst->context->channels; int result; int index; int max_fd, fd; void* read_fds[32]; void* write_fds[32]; int read_count = 0; int write_count = 0; fd_set rfds, wfds; struct timeval timeout = { .tv_sec = 0, .tv_usec = timeout_usecs }; /* Get RDP fds */ if (!freerdp_get_fds(rdp_inst, read_fds, &read_count, write_fds, &write_count)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to read RDP file descriptors."); return -1; } /* Get channel fds */ if (!freerdp_channels_get_fds(channels, rdp_inst, read_fds, &read_count, write_fds, &write_count)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to read RDP channel file descriptors."); return -1; } /* Construct read fd_set */ max_fd = 0; FD_ZERO(&rfds); for (index = 0; index < read_count; index++) { fd = (int)(long) (read_fds[index]); if (fd > max_fd) max_fd = fd; FD_SET(fd, &rfds); } /* Construct write fd_set */ FD_ZERO(&wfds); for (index = 0; index < write_count; index++) { fd = (int)(long) (write_fds[index]); if (fd > max_fd) max_fd = fd; FD_SET(fd, &wfds); } /* If no file descriptors, error */ if (max_fd == 0) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "No file descriptors associated with RDP connection."); return -1; } /* Wait for all RDP file descriptors */ result = select(max_fd + 1, &rfds, &wfds, NULL, &timeout); if (result < 0) { /* If error ignorable, pretend timout occurred */ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == EINTR) return 0; /* Otherwise, return as error */ guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error waiting for file descriptor."); return -1; } /* Return wait result */ return result; } /** * Connects to an RDP server as described by the guac_rdp_settings structure * associated with the given client, allocating and freeing all objects * directly related to the RDP connection. It is expected that all objects * which are independent of FreeRDP's state (the clipboard, display update * management, etc.) will already be allocated and associated with the * guac_rdp_client associated with the given guac_client. This function blocks * for the duration of the RDP session, returning only after the session has * completely disconnected. * * @param client * The guac_client associated with the RDP settings describing the * connection that should be established. * * @return * Zero if the connection successfully terminated and a reconnect is * desired, non-zero if an error occurs or the connection was disconnected * and a reconnect is NOT desired. */ static int guac_rdp_handle_connection(guac_client* client) { guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_settings* settings = rdp_client->settings; /* Init random number generator */ srandom(time(NULL)); /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { guac_common_recording_create(client, settings->recording_path, settings->recording_name, settings->create_recording_path); } /* Create display */ rdp_client->display = guac_common_display_alloc(client, rdp_client->settings->width, rdp_client->settings->height); rdp_client->current_surface = rdp_client->display->default_surface; rdp_client->requested_clipboard_format = CB_FORMAT_TEXT; rdp_client->available_svc = guac_common_list_alloc(); #ifdef HAVE_FREERDP_CHANNELS_GLOBAL_INIT freerdp_channels_global_init(); #endif /* Init client */ freerdp* rdp_inst = freerdp_new(); rdp_inst->PreConnect = rdp_freerdp_pre_connect; rdp_inst->PostConnect = rdp_freerdp_post_connect; rdp_inst->Authenticate = rdp_freerdp_authenticate; rdp_inst->VerifyCertificate = rdp_freerdp_verify_certificate; rdp_inst->ReceiveChannelData = __guac_receive_channel_data; /* Allocate FreeRDP context */ #ifdef LEGACY_FREERDP rdp_inst->context_size = sizeof(rdp_freerdp_context); #else rdp_inst->ContextSize = sizeof(rdp_freerdp_context); #endif rdp_inst->ContextNew = (pContextNew) rdp_freerdp_context_new; rdp_inst->ContextFree = (pContextFree) rdp_freerdp_context_free; freerdp_context_new(rdp_inst); ((rdp_freerdp_context*) rdp_inst->context)->client = client; /* Load keymap into client */ __guac_rdp_client_load_keymap(client, settings->server_layout); /* Send connection name */ guac_protocol_send_name(client->socket, settings->hostname); /* Set default pointer */ guac_common_cursor_set_pointer(rdp_client->display->cursor); /* Push desired settings to FreeRDP */ guac_rdp_push_settings(settings, rdp_inst); /* Connect to RDP server */ if (!freerdp_connect(rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Error connecting to RDP server"); return 1; } /* Connection complete */ rdp_client->rdp_inst = rdp_inst; rdpChannels* channels = rdp_inst->context->channels; guac_timestamp last_frame_end = guac_timestamp_current(); /* Signal that reconnect has been completed */ guac_rdp_disp_reconnect_complete(rdp_client->disp); /* Handle messages from RDP server while client is running */ while (client->state == GUAC_CLIENT_RUNNING && !guac_rdp_disp_reconnect_needed(rdp_client->disp)) { /* Update remote display size */ pthread_mutex_lock(&(rdp_client->rdp_lock)); guac_rdp_disp_update_size(rdp_client->disp, settings, rdp_inst); pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Wait for data and construct a reasonable frame */ int wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_START_TIMEOUT); if (wait_result > 0) { int processing_lag = guac_client_get_processing_lag(client); guac_timestamp frame_start = guac_timestamp_current(); /* Read server messages until frame is built */ do { guac_timestamp frame_end; int frame_remaining; pthread_mutex_lock(&(rdp_client->rdp_lock)); /* Check the libfreerdp fds */ if (!freerdp_check_fds(rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error handling RDP file descriptors"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } /* Check channel fds */ if (!freerdp_channels_check_fds(channels, rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error handling RDP channel file descriptors"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } /* Check for channel events */ wMessage* event = freerdp_channels_pop_event(channels); if (event) { /* Handle channel events (clipboard and RAIL) */ #ifdef LEGACY_EVENT if (event->event_class == CliprdrChannel_Class) guac_rdp_process_cliprdr_event(client, event); else if (event->event_class == RailChannel_Class) guac_rdp_process_rail_event(client, event); #else if (GetMessageClass(event->id) == CliprdrChannel_Class) guac_rdp_process_cliprdr_event(client, event); else if (GetMessageClass(event->id) == RailChannel_Class) guac_rdp_process_rail_event(client, event); #endif freerdp_event_free(event); } /* Handle RDP disconnect */ if (freerdp_shall_disconnect(rdp_inst)) { guac_client_stop(client); guac_client_log(client, GUAC_LOG_INFO, "RDP server closed connection"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Calculate time remaining in frame */ frame_end = guac_timestamp_current(); frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION - frame_end; /* Calculate time that client needs to catch up */ int time_elapsed = frame_end - last_frame_end; int required_wait = processing_lag - time_elapsed; /* Increase the duration of this frame if client is lagging */ if (required_wait > GUAC_RDP_FRAME_TIMEOUT) wait_result = rdp_guac_client_wait_for_messages(client, required_wait*1000); /* Wait again if frame remaining */ else if (frame_remaining > 0) wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_TIMEOUT*1000); else break; } while (wait_result > 0); } /* If an error occurred, fail */ if (wait_result < 0) guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Connection closed."); /* End of frame */ guac_common_display_flush(rdp_client->display); guac_client_end_frame(client); guac_socket_flush(client->socket); /* Record end of frame */ last_frame_end = guac_timestamp_current(); } /* Kill client and finish connection */ guac_client_stop(client); guac_client_log(client, GUAC_LOG_INFO, "Internal RDP client disconnected"); pthread_mutex_lock(&(rdp_client->rdp_lock)); /* Disconnect client and channels */ freerdp_channels_close(channels, rdp_inst); freerdp_channels_free(channels); freerdp_disconnect(rdp_inst); /* Clean up RDP client context */ freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv); cache_free(rdp_inst->context->cache); freerdp_context_free(rdp_inst); /* Clean up RDP client */ freerdp_free(rdp_inst); rdp_client->rdp_inst = NULL; /* Free SVC list */ guac_common_list_free(rdp_client->available_svc); /* Free display */ guac_common_display_free(rdp_client->display); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 0; }
static int android_freerdp_run(freerdp* instance) { int i; int fds; int max_fds; int rcount; int wcount; int fd_input_event; HANDLE input_event; void* rfds[32]; void* wfds[32]; fd_set rfds_set; fd_set wfds_set; int select_status; struct timeval timeout; const rdpSettings* settings = instance->context->settings; HANDLE update_thread; HANDLE input_thread; HANDLE channels_thread; BOOL async_update = settings->AsyncUpdate; BOOL async_input = settings->AsyncInput; BOOL async_channels = settings->AsyncChannels; BOOL async_transport = settings->AsyncTransport; DEBUG_ANDROID("AsyncUpdate=%d", settings->AsyncUpdate); DEBUG_ANDROID("AsyncInput=%d", settings->AsyncInput); DEBUG_ANDROID("AsyncChannels=%d", settings->AsyncChannels); DEBUG_ANDROID("AsyncTransport=%d", settings->AsyncTransport); memset(rfds, 0, sizeof(rfds)); memset(wfds, 0, sizeof(wfds)); if (!freerdp_connect(instance)) { freerdp_callback("OnConnectionFailure", "(I)V", instance); return 0; } if (async_update) { update_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) jni_update_thread, instance, 0, NULL); } if (async_input) { input_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) jni_input_thread, instance, 0, NULL); } if (async_channels) { channels_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) jni_channels_thread, instance, 0, NULL); } ((androidContext*)instance->context)->is_connected = TRUE; while (!freerdp_shall_disconnect(instance)) { rcount = 0; wcount = 0; if (!async_transport) { if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { DEBUG_ANDROID("Failed to get FreeRDP file descriptor\n"); break; } } if (!async_channels) { if (freerdp_channels_get_fds(instance->context->channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) { DEBUG_ANDROID("Failed to get channel manager file descriptor\n"); break; } } if (!async_input) { if (android_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { DEBUG_ANDROID("Failed to get android file descriptor\n"); break; } } else { input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); fd_input_event = GetEventFileDescriptor(input_event); rfds[rcount++] = (void*) (long) fd_input_event; } max_fds = 0; FD_ZERO(&rfds_set); FD_ZERO(&wfds_set); for (i = 0; i < rcount; i++) { fds = (int)(long)(rfds[i]); if (fds > max_fds) max_fds = fds; FD_SET(fds, &rfds_set); } if (max_fds == 0) break; timeout.tv_sec = 1; timeout.tv_usec = 0; select_status = select(max_fds + 1, &rfds_set, NULL, NULL, &timeout); if (select_status == 0) continue; else if (select_status == -1) { /* these are not really errors */ if (!((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { DEBUG_ANDROID("android_run: select failed\n"); break; } } if (freerdp_shall_disconnect(instance)) break; if (!async_transport) { if (freerdp_check_fds(instance) != TRUE) { DEBUG_ANDROID("Failed to check FreeRDP file descriptor\n"); break; } } if (!async_input) { if (android_check_fds(instance) != TRUE) { DEBUG_ANDROID("Failed to check android file descriptor\n"); break; } } else { if (WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0) { if (!freerdp_message_queue_process_pending_messages(instance, FREERDP_INPUT_MESSAGE_QUEUE)) { DEBUG_ANDROID("User Disconnect"); break; } } } if (!async_channels) { if (freerdp_channels_check_fds(instance->context->channels, instance) != TRUE) { DEBUG_ANDROID("Failed to check channel manager file descriptor\n"); break; } android_process_channel_event(instance->context->channels, instance); } } DEBUG_ANDROID("Prepare shutdown..."); // issue another OnDisconnecting here in case the disconnect was initiated by the sever and not our client freerdp_callback("OnDisconnecting", "(I)V", instance); DEBUG_ANDROID("Close channels..."); freerdp_channels_close(instance->context->channels, instance); DEBUG_ANDROID("Cleanup threads..."); if (async_update) { wMessageQueue* update_queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); MessageQueue_PostQuit(update_queue, 0); WaitForSingleObject(update_thread, INFINITE); CloseHandle(update_thread); } if (async_input) { wMessageQueue* input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); MessageQueue_PostQuit(input_queue, 0); WaitForSingleObject(input_thread, INFINITE); CloseHandle(input_thread); } if (async_channels) { WaitForSingleObject(channels_thread, INFINITE); CloseHandle(channels_thread); } DEBUG_ANDROID("Disconnecting..."); freerdp_channels_free(instance->context->channels); freerdp_disconnect(instance); gdi_free(instance); cache_free(instance->context->cache); android_cliprdr_uninit(instance); freerdp_callback("OnDisconnected", "(I)V", instance); DEBUG_ANDROID("Quit."); return 0; }
void* tf_client_thread_proc(freerdp* instance) { int i; int fds; int max_fds; int rcount; int wcount; void* rfds[32]; void* wfds[32]; fd_set rfds_set; fd_set wfds_set; rdpChannels* channels; channels = instance->context->channels; freerdp_connect(instance); while (1) { rcount = 0; wcount = 0; ZeroMemory(rfds, sizeof(rfds)); ZeroMemory(wfds, sizeof(wfds)); if (!freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount)) { WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); break; } if (!freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount)) { WLog_ERR(TAG, "Failed to get channel manager file descriptor"); break; } max_fds = 0; FD_ZERO(&rfds_set); FD_ZERO(&wfds_set); for (i = 0; i < rcount; i++) { fds = (int)(long)(rfds[i]); if (fds > max_fds) max_fds = fds; FD_SET(fds, &rfds_set); } if (max_fds == 0) break; if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1) { /* these are not really errors */ if (!((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { WLog_ERR(TAG, "tfreerdp_run: select failed"); break; } } if (!freerdp_check_fds(instance)) { WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } if (!freerdp_channels_check_fds(channels, instance)) { WLog_ERR(TAG, "Failed to check channel manager file descriptor"); break; } } freerdp_channels_close(channels, instance); freerdp_channels_free(channels); freerdp_free(instance); ExitThread(0); return NULL; }
int wfreerdp_run(freerdp* instance) { MSG msg; int index; int rcount; int wcount; BOOL msg_ret; int quit_msg; void* rfds[32]; void* wfds[32]; int fds_count; HANDLE fds[64]; rdpChannels* channels; memset(rfds, 0, sizeof(rfds)); memset(wfds, 0, sizeof(wfds)); if (freerdp_connect(instance) != true) return 0; channels = instance->context->channels; while (1) { rcount = 0; wcount = 0; if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != true) { printf("Failed to get FreeRDP file descriptor\n"); break; } if (wf_get_fds(instance, rfds, &rcount, wfds, &wcount) != true) { printf("Failed to get wfreerdp file descriptor\n"); break; } if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != true) { printf("Failed to get channel manager file descriptor\n"); break; } fds_count = 0; /* setup read fds */ for (index = 0; index < rcount; index++) { fds[fds_count++] = rfds[index]; } /* setup write fds */ for (index = 0; index < wcount; index++) { fds[fds_count++] = wfds[index]; } /* exit if nothing to do */ if (fds_count == 0) { printf("wfreerdp_run: fds_count is zero\n"); break; } /* do the wait */ if (MsgWaitForMultipleObjects(fds_count, fds, FALSE, 1, QS_ALLINPUT) == WAIT_FAILED) { printf("wfreerdp_run: WaitForMultipleObjects failed: 0x%04X\n", GetLastError()); break; } if (freerdp_check_fds(instance) != true) { printf("Failed to check FreeRDP file descriptor\n"); break; } if (wf_check_fds(instance) != true) { printf("Failed to check wfreerdp file descriptor\n"); break; } if (freerdp_channels_check_fds(channels, instance) != true) { printf("Failed to check channel manager file descriptor\n"); break; } wf_process_channel_event(channels, instance); quit_msg = FALSE; while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { msg_ret = GetMessage(&msg, NULL, 0, 0); if (msg_ret == 0 || msg_ret == -1) { quit_msg = TRUE; break; } TranslateMessage(&msg); DispatchMessage(&msg); } if (quit_msg) break; } /* cleanup */ freerdp_channels_free(channels); freerdp_free(instance); return 0; }
int dfreerdp_run(freerdp* instance) { int i; int fds; int max_fds; int rcount; int wcount; void* rfds[32]; void* wfds[32]; fd_set rfds_set; fd_set wfds_set; dfInfo* dfi; dfContext* context; rdpChannels* channels; ZeroMemory(rfds, sizeof(rfds)); ZeroMemory(wfds, sizeof(wfds)); if (!freerdp_connect(instance)) return 0; context = (dfContext*) instance->context; dfi = context->dfi; channels = instance->context->channels; while (1) { rcount = 0; wcount = 0; if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { fprintf(stderr, "Failed to get FreeRDP file descriptor\n"); break; } if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) { fprintf(stderr, "Failed to get channel manager file descriptor\n"); break; } if (df_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) { fprintf(stderr, "Failed to get dfreerdp file descriptor\n"); break; } max_fds = 0; FD_ZERO(&rfds_set); FD_ZERO(&wfds_set); for (i = 0; i < rcount; i++) { fds = (int)(long)(rfds[i]); if (fds > max_fds) max_fds = fds; FD_SET(fds, &rfds_set); } if (max_fds == 0) break; if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1) { /* these are not really errors */ if (!((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { fprintf(stderr, "dfreerdp_run: select failed\n"); break; } } if (freerdp_check_fds(instance) != TRUE) { fprintf(stderr, "Failed to check FreeRDP file descriptor\n"); break; } if (df_check_fds(instance, &rfds_set) != TRUE) { fprintf(stderr, "Failed to check dfreerdp file descriptor\n"); break; } if (freerdp_channels_check_fds(channels, instance) != TRUE) { fprintf(stderr, "Failed to check channel manager file descriptor\n"); break; } df_process_channel_event(channels, instance); } freerdp_channels_close(channels, instance); freerdp_channels_free(channels); df_free(dfi); gdi_free(instance); freerdp_disconnect(instance); freerdp_free(instance); return 0; }
int tfreerdp_run(freerdp* instance) { int i; int fds; int max_fds; int rcount; int wcount; void* rfds[32]; void* wfds[32]; fd_set rfds_set; fd_set wfds_set; rdpChannels* channels; memset(rfds, 0, sizeof(rfds)); memset(wfds, 0, sizeof(wfds)); channels = instance->context->channels; freerdp_connect(instance); while (1) { rcount = 0; wcount = 0; if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != true) { printf("Failed to get FreeRDP file descriptor\n"); break; } if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != true) { printf("Failed to get channel manager file descriptor\n"); break; } max_fds = 0; FD_ZERO(&rfds_set); for (i = 0; i < rcount; i++) { fds = (int)(long)(rfds[i]); if (fds > max_fds) max_fds = fds; FD_SET(fds, &rfds_set); } if (max_fds == 0) break; if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1) { /* these are not really errors */ if (!((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { printf("tfreerdp_run: select failed\n"); break; } } if (freerdp_check_fds(instance) != true) { printf("Failed to check FreeRDP file descriptor\n"); break; } if (freerdp_channels_check_fds(channels, instance) != true) { printf("Failed to check channel manager file descriptor\n"); break; } tf_process_channel_event(channels, instance); } freerdp_channels_close(channels, instance); freerdp_channels_free(channels); freerdp_free(instance); return 0; }
void android_context_free(freerdp* instance, rdpContext* context) { freerdp_channels_close(instance->context->channels, instance); freerdp_channels_free(context->channels); android_event_queue_uninit(instance); }
//----------------------------------------------------------------------------- void test_rail_plugin(void) { thread_param param; pthread_t thread; rdpChannels* chan_man; rdpSettings settings = { 0 }; freerdp s_inst = { 0 }; freerdp* inst = &s_inst; size_t sn = 0; size_t en = 0; STREAM* ss = NULL; RAIL_EVENT* ee = NULL; printf("\n"); settings.hostname = "testhost"; inst->settings = &settings; inst->SendChannelData = emulate_client_send_channel_data; chan_man = freerdp_channels_new(); freerdp_channels_load_plugin(chan_man, &settings, "../channels/rail/rail.so", NULL); freerdp_channels_pre_connect(chan_man, inst); freerdp_channels_post_connect(chan_man, inst); memset(¶m, 0, sizeof(param)); param.chan_man = chan_man; param.instance = inst; param.th_count = 0; param.th_to_finish = 0; global_thread_params = ¶m; pthread_create(&thread, 0, thread_func, ¶m); // 1. Emulate server handshake binary EMULATE_SERVER_SEND_CHANNEL_DATA(inst, server_handshake); EMULATE_SERVER_SEND_CHANNEL_DATA(inst, server_exec_result_pdu); EMULATE_SERVER_SEND_CHANNEL_DATA(inst, server_sysparam1_pdu); EMULATE_SERVER_SEND_CHANNEL_DATA(inst, server_sysparam2_pdu); EMULATE_SERVER_SEND_CHANNEL_DATA(inst, server_localmovesize_start_pdu); EMULATE_SERVER_SEND_CHANNEL_DATA(inst, server_localmovesize_stop_pdu); EMULATE_SERVER_SEND_CHANNEL_DATA(inst, server_minmaxinfo_pdu); EMULATE_SERVER_SEND_CHANNEL_DATA(inst, server_langbar_pdu); EMULATE_SERVER_SEND_CHANNEL_DATA(inst, server_app_get_resp_pdu); // 2. Send UI events param.out_rail_orders.sysparam.params = 0; param.out_rail_orders.sysparam.params |= SPI_MASK_SET_HIGH_CONTRAST; param.out_rail_orders.sysparam.highContrast.flags = 0x7e; param.out_rail_orders.sysparam.highContrast.colorScheme.length = 0; param.out_rail_orders.sysparam.highContrast.colorScheme.string = NULL; param.out_rail_orders.sysparam.params |= SPI_MASK_TASKBAR_POS; param.out_rail_orders.sysparam.taskbarPos.left = 0; param.out_rail_orders.sysparam.taskbarPos.top = 0x039a; param.out_rail_orders.sysparam.taskbarPos.right = 0x0690; param.out_rail_orders.sysparam.taskbarPos.bottom = 0x03c2; param.out_rail_orders.sysparam.params |= SPI_MASK_SET_MOUSE_BUTTON_SWAP; param.out_rail_orders.sysparam.mouseButtonSwap = False; param.out_rail_orders.sysparam.params |= SPI_MASK_SET_KEYBOARD_PREF; param.out_rail_orders.sysparam.keyboardPref = False; param.out_rail_orders.sysparam.params |= SPI_MASK_SET_DRAG_FULL_WINDOWS; param.out_rail_orders.sysparam.dragFullWindows = True; param.out_rail_orders.sysparam.params |= SPI_MASK_SET_KEYBOARD_CUES; param.out_rail_orders.sysparam.keyboardCues = False; param.out_rail_orders.sysparam.params |= SPI_MASK_SET_WORK_AREA; param.out_rail_orders.sysparam.workArea.left = 0; param.out_rail_orders.sysparam.workArea.top = 0; param.out_rail_orders.sysparam.workArea.right = 0x0690; param.out_rail_orders.sysparam.workArea.bottom = 0x039a; send_ui_event2plugin(chan_man, RDP_EVENT_TYPE_RAIL_CLIENT_SET_SYSPARAMS, ¶m.out_rail_orders.sysparam); param.plugin_data.size = sizeof(RDP_PLUGIN_DATA); param.plugin_data.data[0] = "||iexplore"; param.plugin_data.data[1] = "f:\\windows\\system32"; param.plugin_data.data[2] = "www.bing.com"; send_ui_event2plugin(chan_man, RDP_EVENT_TYPE_RAIL_CLIENT_EXEC_REMOTE_APP, ¶m.plugin_data); param.out_rail_orders.activate.enabled = True; param.out_rail_orders.activate.windowId = 0x0007008e; send_ui_event2plugin(chan_man, RDP_EVENT_TYPE_RAIL_CLIENT_ACTIVATE, ¶m.out_rail_orders.activate); param.out_rail_orders.syscommand.windowId = 0x00020052; param.out_rail_orders.syscommand.command = 0xf020; send_ui_event2plugin(chan_man, RDP_EVENT_TYPE_RAIL_CLIENT_SYSCOMMAND, ¶m.out_rail_orders.syscommand); param.out_rail_orders.notify_event.windowId = 0x000201aa; param.out_rail_orders.notify_event.notifyIconId = 0x02; param.out_rail_orders.notify_event.message = 0x0204; send_ui_event2plugin(chan_man, RDP_EVENT_TYPE_RAIL_CLIENT_NOTIFY_EVENT, ¶m.out_rail_orders.notify_event); param.out_rail_orders.window_move.windowId = 0x00020020; param.out_rail_orders.window_move.left = 0x0309; param.out_rail_orders.window_move.top = 0x0100; param.out_rail_orders.window_move.right = 0x05db; param.out_rail_orders.window_move.bottom = 0x0188; send_ui_event2plugin(chan_man, RDP_EVENT_TYPE_RAIL_CLIENT_WINDOW_MOVE, ¶m.out_rail_orders.window_move); param.out_rail_orders.sysmenu.windowId = 0x00090122; param.out_rail_orders.sysmenu.left = 0xffa4; // TODO: possible negative values? param.out_rail_orders.sysmenu.top = 0x024a; send_ui_event2plugin(chan_man, RDP_EVENT_TYPE_RAIL_CLIENT_SYSMENU, ¶m.out_rail_orders.sysmenu); param.out_rail_orders.langbar_info.languageBarStatus = 0x00000001; send_ui_event2plugin(chan_man, RDP_EVENT_TYPE_RAIL_CLIENT_LANGBARINFO, ¶m.out_rail_orders.langbar_info); param.out_rail_orders.get_appid_req.windowId = 0x00020052; send_ui_event2plugin(chan_man, RDP_EVENT_TYPE_RAIL_CLIENT_APPID_REQ, ¶m.out_rail_orders.get_appid_req); // Waiting for possible events or data sleep(1); // Finishing thread and wait for it param.th_to_finish = 1; while (param.th_count > 0) { usleep(1000); } // We need to collected all events and data dumps and then to. // create CU_ASSERT series here! sn = param.in_streams_number; en = param.in_events_number; ss = ¶m.in_streams[0]; ee = ¶m.in_events[0]; CU_ASSERT(sn > 0 && STREAM_EQUAL_TO_DUMP(&ss[ 0], client_handshake)); CU_ASSERT(sn > 1 && STREAM_EQUAL_TO_DUMP(&ss[ 1], client_info_pdu)); CU_ASSERT(sn > 2 && STREAM_EQUAL_TO_DUMP(&ss[ 2], client_sysparam_highcontrast_pdu)); CU_ASSERT(sn > 3 && STREAM_EQUAL_TO_DUMP(&ss[ 3], client_sysparam_taskbarpos_pdu)); CU_ASSERT(sn > 4 && STREAM_EQUAL_TO_DUMP(&ss[ 4], client_sysparam_mousebuttonswap_pdu)); CU_ASSERT(sn > 5 && STREAM_EQUAL_TO_DUMP(&ss[ 5], client_sysparam_keyboardpref_pdu)); CU_ASSERT(sn > 6 && STREAM_EQUAL_TO_DUMP(&ss[ 6], client_sysparam_dragfullwindow_pdu)); CU_ASSERT(sn > 7 && STREAM_EQUAL_TO_DUMP(&ss[ 7], client_sysparam_keyboardcues_pdu)); CU_ASSERT(sn > 8 && STREAM_EQUAL_TO_DUMP(&ss[ 8], client_sysparam_setworkarea_pdu)); CU_ASSERT(sn > 9 && STREAM_EQUAL_TO_DUMP(&ss[ 9], client_execute_pdu)); CU_ASSERT(sn >10 && STREAM_EQUAL_TO_DUMP(&ss[10], client_activate_pdu)); CU_ASSERT(sn >11 && STREAM_EQUAL_TO_DUMP(&ss[11], client_syscommand_pdu)); CU_ASSERT(sn >12 && STREAM_EQUAL_TO_DUMP(&ss[12], client_notify_pdu)); CU_ASSERT(sn >13 && STREAM_EQUAL_TO_DUMP(&ss[13], client_windowmove_pdu)); CU_ASSERT(sn >14 && STREAM_EQUAL_TO_DUMP(&ss[14], client_system_menu_pdu)); CU_ASSERT(sn >15 && STREAM_EQUAL_TO_DUMP(&ss[15], client_langbar_pdu)); CU_ASSERT(sn >16 && STREAM_EQUAL_TO_DUMP(&ss[16], client_get_app_id_req_pdu)); CU_ASSERT(en > 0 && ee[ 0].event_type == RDP_EVENT_TYPE_RAIL_CHANNEL_GET_SYSPARAMS); CU_ASSERT(en > 1 && ee[ 1].event_type == RDP_EVENT_TYPE_RAIL_CHANNEL_EXEC_RESULTS && ee[ 1].order_info.exec_result.flags == 0x08 && ee[ 1].order_info.exec_result.execResult == 0x03 && UNICODE_STRING_EQUAL_TO_DUMP( &ee[ 1].order_info.exec_result.exeOrFile, server_exec_result_exe_or_file) ); CU_ASSERT(en > 2 && ee[ 2].event_type == RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_SYSPARAM && ee[ 2].order_info.sysparam.setScreenSaveSecure == False ); CU_ASSERT(en > 3 && ee[ 3].event_type == RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_SYSPARAM && ee[ 3].order_info.sysparam.setScreenSaveActive == False ); CU_ASSERT(en > 4 && ee[ 4].event_type == RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_LOCALMOVESIZE && ee[ 4].order_info.localmovesize.windowId == 0x0007008e && ee[ 4].order_info.localmovesize.isMoveSizeStart == True && ee[ 4].order_info.localmovesize.moveSizeType == RAIL_WMSZ_MOVE && ee[ 4].order_info.localmovesize.posX == 0x017e && ee[ 4].order_info.localmovesize.posY == 0x000a ); CU_ASSERT(en > 5 && ee[ 5].event_type == RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_LOCALMOVESIZE && ee[ 5].order_info.localmovesize.windowId == 0x0007008e && ee[ 5].order_info.localmovesize.isMoveSizeStart == False && ee[ 5].order_info.localmovesize.moveSizeType == RAIL_WMSZ_MOVE && ee[ 5].order_info.localmovesize.posX == 0x00a6 && ee[ 5].order_info.localmovesize.posY == 0x0044 ); CU_ASSERT(en > 6 && ee[ 6].event_type == RDP_EVENT_TYPE_RAIL_CHANNEL_SERVER_MINMAXINFO && ee[ 6].order_info.minmaxinfo.windowId == 0x0007008e && ee[ 6].order_info.minmaxinfo.maxWidth == 0x0408 && ee[ 6].order_info.minmaxinfo.maxHeight == 0x02d6 && ee[ 6].order_info.minmaxinfo.maxPosX == 0x0000 && ee[ 6].order_info.minmaxinfo.maxPosY == 0x0000 && ee[ 6].order_info.minmaxinfo.minTrackWidth == 0x0070 && ee[ 6].order_info.minmaxinfo.minTrackHeight == 0x001b && ee[ 6].order_info.minmaxinfo.maxTrackWidth == 0x040c && ee[ 6].order_info.minmaxinfo.maxTrackHeight == 0x030c ); CU_ASSERT(en > 7 && ee[ 7].event_type == RDP_EVENT_TYPE_RAIL_CHANNEL_LANGBARINFO && ee[ 7].order_info.langbar_info.languageBarStatus == TF_SFT_SHOWNORMAL ); CU_ASSERT(en > 8 && ee[ 8].event_type == RDP_EVENT_TYPE_RAIL_CHANNEL_APPID_RESP && ee[ 8].order_info.get_appid_resp.windowId == 0x00020052 && UNICODE_STRING_EQUAL_TO_DUMP( &ee[ 8].order_info.get_appid_resp.applicationId, server_app_get_resp_app_id ) ); freerdp_channels_close(chan_man, inst); freerdp_channels_free(chan_man); }
/** * Connects to an RDP server as described by the guac_rdp_settings structure * associated with the given client, allocating and freeing all objects * directly related to the RDP connection. It is expected that all objects * which are independent of FreeRDP's state (the clipboard, display update * management, etc.) will already be allocated and associated with the * guac_rdp_client associated with the given guac_client. This function blocks * for the duration of the RDP session, returning only after the session has * completely disconnected. * * @param client * The guac_client associated with the RDP settings describing the * connection that should be established. * * @return * Zero if the connection successfully terminated and a reconnect is * desired, non-zero if an error occurs or the connection was disconnected * and a reconnect is NOT desired. */ static int guac_rdp_handle_connection(guac_client* client) { guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; guac_rdp_settings* settings = rdp_client->settings; /* Init random number generator */ srandom(time(NULL)); /* Set up screen recording, if requested */ if (settings->recording_path != NULL) { guac_common_recording_create(client, settings->recording_path, settings->recording_name, settings->create_recording_path); } /* Create display */ rdp_client->display = guac_common_display_alloc(client, rdp_client->settings->width, rdp_client->settings->height); rdp_client->current_surface = rdp_client->display->default_surface; rdp_client->requested_clipboard_format = CB_FORMAT_TEXT; rdp_client->available_svc = guac_common_list_alloc(); #ifdef HAVE_FREERDP_CHANNELS_GLOBAL_INIT freerdp_channels_global_init(); #endif /* Init client */ freerdp* rdp_inst = freerdp_new(); rdp_inst->PreConnect = rdp_freerdp_pre_connect; rdp_inst->PostConnect = rdp_freerdp_post_connect; rdp_inst->Authenticate = rdp_freerdp_authenticate; rdp_inst->VerifyCertificate = rdp_freerdp_verify_certificate; rdp_inst->ReceiveChannelData = __guac_receive_channel_data; /* Allocate FreeRDP context */ #ifdef LEGACY_FREERDP rdp_inst->context_size = sizeof(rdp_freerdp_context); #else rdp_inst->ContextSize = sizeof(rdp_freerdp_context); #endif rdp_inst->ContextNew = (pContextNew) rdp_freerdp_context_new; rdp_inst->ContextFree = (pContextFree) rdp_freerdp_context_free; freerdp_context_new(rdp_inst); ((rdp_freerdp_context*) rdp_inst->context)->client = client; /* Load keymap into client */ rdp_client->keyboard = guac_rdp_keyboard_alloc(client, settings->server_layout); /* Send connection name */ guac_protocol_send_name(client->socket, settings->hostname); /* Set default pointer */ guac_common_cursor_set_pointer(rdp_client->display->cursor); /* Push desired settings to FreeRDP */ guac_rdp_push_settings(settings, rdp_inst); /* Connect to RDP server */ if (!freerdp_connect(rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Error connecting to RDP server"); return 1; } /* Connection complete */ rdp_client->rdp_inst = rdp_inst; rdpChannels* channels = rdp_inst->context->channels; guac_timestamp last_frame_end = guac_timestamp_current(); /* Signal that reconnect has been completed */ guac_rdp_disp_reconnect_complete(rdp_client->disp); /* Handle messages from RDP server while client is running */ while (client->state == GUAC_CLIENT_RUNNING && !guac_rdp_disp_reconnect_needed(rdp_client->disp)) { /* Update remote display size */ pthread_mutex_lock(&(rdp_client->rdp_lock)); guac_rdp_disp_update_size(rdp_client->disp, settings, rdp_inst); pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Wait for data and construct a reasonable frame */ int wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_START_TIMEOUT); if (wait_result > 0) { int processing_lag = guac_client_get_processing_lag(client); guac_timestamp frame_start = guac_timestamp_current(); /* Read server messages until frame is built */ do { guac_timestamp frame_end; int frame_remaining; pthread_mutex_lock(&(rdp_client->rdp_lock)); /* Check the libfreerdp fds */ if (!freerdp_check_fds(rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error handling RDP file descriptors"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } /* Check channel fds */ if (!freerdp_channels_check_fds(channels, rdp_inst)) { guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Error handling RDP channel file descriptors"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } /* Check for channel events */ wMessage* event = freerdp_channels_pop_event(channels); if (event) { /* Handle channel events (clipboard and RAIL) */ #ifdef LEGACY_EVENT if (event->event_class == CliprdrChannel_Class) guac_rdp_process_cliprdr_event(client, event); else if (event->event_class == RailChannel_Class) guac_rdp_process_rail_event(client, event); #else if (GetMessageClass(event->id) == CliprdrChannel_Class) guac_rdp_process_cliprdr_event(client, event); else if (GetMessageClass(event->id) == RailChannel_Class) guac_rdp_process_rail_event(client, event); #endif freerdp_event_free(event); } /* Handle RDP disconnect */ if (freerdp_shall_disconnect(rdp_inst)) { guac_client_stop(client); guac_client_log(client, GUAC_LOG_INFO, "RDP server closed connection"); pthread_mutex_unlock(&(rdp_client->rdp_lock)); return 1; } pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Calculate time remaining in frame */ frame_end = guac_timestamp_current(); frame_remaining = frame_start + GUAC_RDP_FRAME_DURATION - frame_end; /* Calculate time that client needs to catch up */ int time_elapsed = frame_end - last_frame_end; int required_wait = processing_lag - time_elapsed; /* Increase the duration of this frame if client is lagging */ if (required_wait > GUAC_RDP_FRAME_TIMEOUT) wait_result = rdp_guac_client_wait_for_messages(client, required_wait); /* Wait again if frame remaining */ else if (frame_remaining > 0) wait_result = rdp_guac_client_wait_for_messages(client, GUAC_RDP_FRAME_TIMEOUT); else break; } while (wait_result > 0); /* Record end of frame, excluding server-side rendering time (we * assume server-side rendering time will be consistent between any * two subsequent frames, and that this time should thus be * excluded from the required wait period of the next frame). */ last_frame_end = frame_start; } /* If an error occurred, fail */ if (wait_result < 0) guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_ERROR, "Connection closed."); /* Flush frame */ guac_common_display_flush(rdp_client->display); guac_client_end_frame(client); guac_socket_flush(client->socket); } pthread_mutex_lock(&(rdp_client->rdp_lock)); /* Disconnect client and channels */ freerdp_channels_close(channels, rdp_inst); freerdp_channels_free(channels); freerdp_disconnect(rdp_inst); /* Clean up RDP client context */ freerdp_clrconv_free(((rdp_freerdp_context*) rdp_inst->context)->clrconv); cache_free(rdp_inst->context->cache); freerdp_context_free(rdp_inst); /* Clean up RDP client */ freerdp_free(rdp_inst); rdp_client->rdp_inst = NULL; /* Free SVC list */ guac_common_list_free(rdp_client->available_svc); /* Free RDP keyboard state */ guac_rdp_keyboard_free(rdp_client->keyboard); /* Free display */ guac_common_display_free(rdp_client->display); pthread_mutex_unlock(&(rdp_client->rdp_lock)); /* Client is now disconnected */ guac_client_log(client, GUAC_LOG_INFO, "Internal RDP client disconnected"); return 0; }