int main(int argc, char* argv[]) { int status; freerdp* instance; instance = freerdp_new(); instance->PreConnect = wl_pre_connect; instance->PostConnect = wl_post_connect; instance->PostDisconnect = wl_post_disconnect; instance->VerifyCertificate = wl_verify_certificate; instance->ContextSize = sizeof(wlfContext); instance->ContextNew = wl_context_new; instance->ContextFree = wl_context_free; freerdp_context_new(instance); status = freerdp_client_settings_parse_command_line_arguments(instance->settings, argc, argv, FALSE); status = freerdp_client_settings_command_line_status_print(instance->settings, status, argc, argv); if (status) exit(0); freerdp_client_load_addins(instance->context->channels, instance->settings); wlfreerdp_run(instance); freerdp_context_free(instance); freerdp_free(instance); return 0; }
void freerdp_client_context_free(rdpContext* context) { freerdp* instance = context->instance; freerdp_context_free(instance); freerdp_free(instance); }
void freerdp_client_context_free(rdpContext* context) { freerdp* instance = context->instance; free(instance->pClientEntryPoints); freerdp_context_free(instance); freerdp_free(instance); }
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; }
int wf_free(wfInfo* wfi) { freerdp* instance = wfi->instance; freerdp_context_free(instance); freerdp_free(instance); return 0; }
JNIEXPORT void JNICALL jni_freerdp_free(JNIEnv *env, jclass cls, jint instance) { freerdp* inst = (freerdp*)instance; freerdp_context_free(inst); freerdp_free(inst); #if defined(WITH_GPROF) moncleanup(); #endif }
int main(int argc, char* argv[]) { int status; HANDLE thread; freerdp* instance; instance = freerdp_new(); if (!instance) { WLog_ERR(TAG, "Couldn't create instance"); return 1; } instance->PreConnect = tf_pre_connect; instance->PostConnect = tf_post_connect; instance->ContextSize = sizeof(tfContext); instance->ContextNew = tf_context_new; instance->ContextFree = tf_context_free; freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); if (!freerdp_context_new(instance)) { WLog_ERR(TAG, "Couldn't create context"); return 1; } status = freerdp_client_settings_parse_command_line(instance->settings, argc, argv, FALSE); if (status < 0) { return 0; } if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) return -1; if (!(thread = CreateThread(NULL, 0, tf_client_thread_proc, instance, 0, NULL))) { WLog_ERR(TAG, "Failed to create client thread"); } else { WaitForSingleObject(thread, INFINITE); } freerdp_context_free(instance); freerdp_free(instance); return 0; }
int main(int argc, char* argv[]) { UwacReturnCode status; freerdp* instance; g_display = UwacOpenDisplay(NULL, &status); if (!g_display) exit(1); g_displayHandle = CreateFileDescriptorEvent(NULL, FALSE, FALSE, UwacDisplayGetFd(g_display), WINPR_FD_READ); if (!g_displayHandle) exit(1); //if (!handle_uwac_events(NULL, g_display)) // exit(1); instance = freerdp_new(); instance->PreConnect = wl_pre_connect; instance->PostConnect = wl_post_connect; instance->PostDisconnect = wl_post_disconnect; instance->Authenticate = client_cli_authenticate; instance->GatewayAuthenticate = client_cli_gw_authenticate; instance->VerifyCertificate = client_cli_verify_certificate; instance->VerifyChangedCertificate = client_cli_verify_changed_certificate; instance->ContextSize = sizeof(wlfContext); instance->ContextNew = wl_context_new; instance->ContextFree = wl_context_free; freerdp_context_new(instance); status = freerdp_client_settings_parse_command_line_arguments(instance->settings, argc, argv, FALSE); status = freerdp_client_settings_command_line_status_print(instance->settings, status, argc, argv); if (status) exit(0); freerdp_client_load_addins(instance->context->channels, instance->settings); wlfreerdp_run(instance); freerdp_context_free(instance); freerdp_free(instance); return 0; }
static int runInstance(int argc, char* argv[], freerdp** inst) { int rc = -1; freerdp* instance = freerdp_new(); if (!instance) goto finish; if (inst) *inst = instance; if (!freerdp_context_new(instance)) goto finish; if (freerdp_client_settings_parse_command_line(instance->settings, argc, argv, FALSE) < 0) goto finish; if (!freerdp_client_load_addins(instance->context->channels, instance->settings)) goto finish; if (s_sync) { if (!SetEvent(s_sync)) goto finish; } rc = 1; if (!freerdp_connect(instance)) goto finish; rc = 2; if (!freerdp_disconnect(instance)) goto finish; rc = 0; finish: freerdp_context_free(instance); freerdp_free(instance); return rc; }
void freerdp_client_context_free(rdpContext* context) { freerdp* instance; if (!context) return; instance = context->instance; if (instance) { RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints; freerdp_context_free(instance); if (pEntryPoints) IFCALL(pEntryPoints->GlobalUninit); free(instance->pClientEntryPoints); freerdp_free(instance); } }
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { freerdp* instance; thread_data* data; WSADATA wsa_data; WNDCLASSEX wnd_cls; if (NULL == getenv("HOME")) { char home[MAX_PATH * 2] = "HOME="; strcat(home, getenv("HOMEDRIVE")); strcat(home, getenv("HOMEPATH")); _putenv(home); } if (WSAStartup(0x101, &wsa_data) != 0) return 1; g_done_event = CreateEvent(0, 1, 0, 0); #if defined(WITH_DEBUG) || defined(_DEBUG) wf_create_console(); #endif g_default_cursor = LoadCursor(NULL, IDC_ARROW); wnd_cls.cbSize = sizeof(WNDCLASSEX); wnd_cls.style = CS_HREDRAW | CS_VREDRAW; wnd_cls.lpfnWndProc = wf_event_proc; wnd_cls.cbClsExtra = 0; wnd_cls.cbWndExtra = 0; wnd_cls.hIcon = LoadIcon(NULL, IDI_APPLICATION); wnd_cls.hCursor = g_default_cursor; wnd_cls.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wnd_cls.lpszMenuName = NULL; wnd_cls.lpszClassName = g_wnd_class_name; wnd_cls.hInstance = hInstance; wnd_cls.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wnd_cls); g_hInstance = hInstance; freerdp_channels_global_init(); instance = freerdp_new(); instance->PreConnect = wf_pre_connect; instance->PostConnect = wf_post_connect; instance->VerifyCertificate = wf_verify_certificate; instance->ReceiveChannelData = wf_receive_channel_data; instance->context_size = sizeof(wfContext); instance->ContextNew = wf_context_new; instance->ContextFree = wf_context_free; freerdp_context_new(instance); instance->context->argc = __argc; instance->context->argv = __argv; #ifdef WITH_RDPDR REGISTER_SVC_PLUGIN_ENTRY(rdpdr); REGISTER_DEV_PLUGIN_ENTRY(disk); REGISTER_DEV_PLUGIN_ENTRY(printer); #endif if (!CreateThread(NULL, 0, kbd_thread_func, NULL, 0, NULL)) printf("error creating keyboard handler thread"); //while (1) { int arg_parse_result; data = (thread_data*) xzalloc(sizeof(thread_data)); data->instance = instance; arg_parse_result = freerdp_parse_args(instance->settings, __argc, __argv, wf_process_plugin_args, instance->context->channels, wf_process_client_args, NULL); if (arg_parse_result < 0) { if (arg_parse_result == FREERDP_ARGS_PARSE_FAILURE) printf("failed to parse arguments.\n"); #ifdef _DEBUG system("pause"); #endif exit(-1); } if (CreateThread(NULL, 0, thread_func, data, 0, NULL) != 0) g_thread_count++; } if (g_thread_count > 0) WaitForSingleObject(g_done_event, INFINITE); else MessageBox(GetConsoleWindow(), L"Failed to start wfreerdp.\n\nPlease check the debug output.", L"FreeRDP Error", MB_ICONSTOP); freerdp_context_free(instance); freerdp_free(instance); WSACleanup(); #ifdef _DEBUG system("pause"); #endif return 0; }
/** * 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; }
/** Allocator function for a rdp context. * The function will allocate a rdpRdp structure using rdp_new(), then copy * its contents to the appropriate fields in the rdp_freerdp structure given in parameters. * It will also initialize the 'context' field in the rdp_freerdp structure as needed. * If the caller has set the ContextNew callback in the 'instance' parameter, it will be called at the end of the function. * * @param instance - Pointer to the rdp_freerdp structure that will be initialized with the new context. */ BOOL freerdp_context_new(freerdp* instance) { rdpRdp* rdp; rdpContext* context; BOOL ret = TRUE; DWORD flags = WINPR_SSL_INIT_DEFAULT; instance->context = (rdpContext*) calloc(1, instance->ContextSize); if (!instance->context) return FALSE; context = instance->context; context->instance = instance; context->ServerMode = FALSE; context->settings = instance->settings; context->pubSub = PubSub_New(TRUE); if (!context->pubSub) goto fail; PubSub_AddEventTypes(context->pubSub, FreeRDP_Events, sizeof(FreeRDP_Events) / sizeof(wEventType)); context->metrics = metrics_new(context); if (!context->metrics) goto fail; rdp = rdp_new(context); if (!rdp) goto fail; instance->input = rdp->input; instance->update = rdp->update; instance->settings = rdp->settings; instance->autodetect = rdp->autodetect; context->graphics = graphics_new(context); if (!context->graphics) goto fail; context->rdp = rdp; context->input = instance->input; context->update = instance->update; context->settings = instance->settings; context->autodetect = instance->autodetect; instance->update->context = instance->context; instance->update->pointer->context = instance->context; instance->update->primary->context = instance->context; instance->update->secondary->context = instance->context; instance->update->altsec->context = instance->context; instance->input->context = context; instance->autodetect->context = context; if (!(context->errorDescription = calloc(1, 500))) { WLog_ERR(TAG, "calloc failed!"); goto fail; } if (!(context->channelErrorEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { WLog_ERR(TAG, "CreateEvent failed!"); goto fail; } update_register_client_callbacks(rdp->update); instance->context->abortEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!instance->context->abortEvent) goto fail; if (!(context->channels = freerdp_channels_new(instance))) goto fail; IFCALLRET(instance->ContextNew, ret, instance, instance->context); if (ret) return TRUE; fail: freerdp_context_free(instance); return FALSE; }
/** * 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; }