diff --git a/CMakeLists.txt b/CMakeLists.txt index 80531b497..22c361b1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,10 @@ if(MSVC) message(STATUS "Random freeing errors are a common sign of runtime issues") endif() configure_msvc_runtime() + + if(NOT DEFINED CMAKE_SUPPRESS_REGENERATION) + set(CMAKE_SUPPRESS_REGENERATION ON) + endif() endif() # Compiler-specific flags diff --git a/client/Android/FreeRDPCore/res/values-es/strings.xml b/client/Android/FreeRDPCore/res/values-es/strings.xml new file mode 100644 index 000000000..2f9d36d8e --- /dev/null +++ b/client/Android/FreeRDPCore/res/values-es/strings.xml @@ -0,0 +1,175 @@ + + + + Si + No + Cancelar + Continuar + Ingresar + Salir + + Salida + Sobre + Ayuda + Nueva conexión + Configuracion + + Conexión + Conectar + Editar + Borrar + + Teclado + Funcion teclado + Puntero Tactil + Inicio + desconectart + + Conexión Manual + Sesiones Activas + + Connectarse a iWinCloud + + Login + No hay escritorios virtuales + Conectando ... + Desconectando ... + Conexión perdida + Contraseña equivocada + Usuario Invalido + Agregar escritorio virtual de iWinCloud + + Host + Su nombre + IP + Puerto + Credenciales de iWinCloud + Credenciales + Usuario + Contraseña + Dominio + Configuracion + Pantalla + Configuracion Pantalla + Colores + + Calidad Normal (16 Bit) + Calidad Optima (24 Bit) + Calidad maxima (32 Bit) + + + 16 + 24 + 32 + + Resolucion + Automatico + Manual + + Automatico + Manual + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + + automatico + manual + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + Ancho + Altura + Rendimiento + Configuracion Rendimiento + RemoteFX + Fondo escritorio + Fuente suave + Composicion escritorio + Contenidos de la ventana mientras se arrastra + Animacion del menu + Estilo visual + Avanzado + Configuracion Avanzada + Configuracion 3G + Pantalla 3G + Rendimiento 3G + Seguridad + + Automatico + RDP + TLS + NLA + + + 0 + 1 + 2 + 3 + + Programa Remoto + Directorio de trabajo + Modo Consola + + ******* + no configurado + Interfaze Usuario + Ocultar barra de estado + Ocultar controles de zoom + Intercambiar botones del mouse + invertir desplazamiento + Puntero táctil de desplazamiento automático + Mostrar cuadro de diálogo en la salida + Ahorro de energía + Cerrar las conexiones inactivas + Seguridad + Aceptar todos los certificados + Borrar el Cache de los certificados + Despues %1$d Minutos + Desabilitado + + Configuración de la conexión + Configuración + iWinCloud - iWinCloud para Android + Conexiones RDP + Ayuda + Sobre + + Cancelar sin guardar? + Pulse el botón "Cancelar" para abortar! \ NPulse "Continuar" para especificar los campos obligatorios! + No se pudo establecer una conexión con iWinCloud! + + Los ajustes de pantalla se han cambiado porque el escritorio virtual no es compatible con la configuración especificada! + Eliminado el cache del certificado! + No se pudo borrar el caché del certificado! + + verificar el certificado + La identidad de su escritorio de iWinCloud debe ser verificada. ¿Desea conectarse de todos modos? + Por favor, introduzca sus credenciales + Crear acceso directo + Nombre corto: + Conectando ... + Ingresando a ... + Sobre iWinCloud + Version: %1$s\n\u00A9 2012 iWinCloud LLc + Guardar configuración de conexión? + La configuración de conexión no se han guardado! ¿Quieres guardarlos? + Guardar Conexión + ¿Desea guardar los cambios realizados en la configuración de conexión? + No volver a preguntar + Salir del programa? + Esta seguro que desea salir del programa? + Borrar Certificados? + Esta seguro que desea borrar todos los certificados? + diff --git a/client/Android/FreeRDPCore/res/values-fr/strings.xml b/client/Android/FreeRDPCore/res/values-fr/strings.xml new file mode 100644 index 000000000..95f3d6490 --- /dev/null +++ b/client/Android/FreeRDPCore/res/values-fr/strings.xml @@ -0,0 +1,174 @@ + + + "Oui" + "Non" + "Annuler" + "Continuer" + "Se connecter" + "Déconnexion" + + "Quitter" + "À propos" + "Aide" + "Nouvelle connexion" + "Paramètres" + + "Connexion" + "Connexion" + "Éditer" + "Supprimer" + + "Clavier" + "Touches de fonction" + "Pointeur tactile" + "Accueil" + "Se déconnecter" + + "Connexions manuelles" + "Sessions actives" + + "Connexion à l'ordinateur" + + "Se connecter" + "Pas de connexion" + "Connexion..." + "Déconnexion…" + "Perte de la connexion" + "Mot de passe incorrect" + "Nom d'utilisateur invalide" + "Ajouter une connexion" + + "Hôte" + "Étiquette" + "Hôte" + "Port" + "Authentifiant" + "Authentifiant" + "Nom d'utilisateur" + "Mot de passe" + "Nom de domaine" + "Paramètres" + "Écran" + "Paramètres d'écran" + "Couleurs" + + "Hautes couleurs (16 bits)" + "Couleurs vraies (24 bits)" + "Haute qualité (32 bits)" + + + "16" + "24" + "32" + + "Résolution" + "Automatique" + "Personalisé" + + "Automatique" + "Personalisé" + "640x480" + "720x480" + "800x600" + "1024x768" + "1280x1024" + "1440x900" + "1920x1080" + "1920x1200" + + + "Automatique" + "Personalisé" + "640x480" + "720x480" + "800x600" + "1024x768" + "1280x1024" + "1440x900" + "1920x1080" + "1920x1200" + + "Largeur" + "Hauteur" + "Performance" + "Paramètres de performance" + "RemoteFX" + "Fond d'écran" + "Lissage des polices" + "Effets visuels Aero" + "Afficher le contenu des fenêtres en mouvement" + "Animations de menu" + "Styles visuels" + "Avancé" + "Paramètres avancés" + "Paramètres 3G" + "Écran 3G" + "Performance 3G" + "Securité" + + "Automatique" + "RDP" + "TLS" + "NLA" + + + "0" + "1" + "2" + "3" + + "Lancement de programme" + "Répertoire de travail" + "Mode console" + + "*******" + "Valeur non définie" + "Interface utilisateur" + "Masquer la barre d'état" + "Masquer les contrôles zoom" + "Inverser les boutons de la souris" + "Inverser le défilement de la souris" + "Défilement automatique du pointeur tactile" + "Confirmer au moment de quitter" + "Economie d'énergie" + "Fermer les connexions inactives" + "Securité" + "Accepter tous les certificats" + "Vider la cache de certificats" + "Après %1$d minutes" + "Désactivé" + + "Paramètres de connexion" + "Paramètres" + "aFreeRDP - FreeRDP pour Android" + "Connexions RDP" + "Aide" + "À propos" + + "Annuler sans enregistrer?" + "Appuyez sur \"Annuler\" pour annuler, ou cliquez sur «Continuer» pour spécifier les champs obligatoires." + "Impossible d'établir une connexion au serveur!" + + "Les paramètres de l'écran ont changé parce que le serveur ne prend pas en charge les paramètres que vous avez spécifiés!" + "La cache de certificats a été supprimée!" + "Impossible de supprimer la cache de certificat!" + + "Validation de certificat" + "L'identité de l'ordinateur distant ne peut pas être vérifiée. Voulez-vous poursuivre la connexion?" + "Veuillez entrer votre nom d'usager et mot de passe" + "Créer un raccourci" + "Nom du raccourci:" + "Connexion..." + "Connexion..." + "À propos de aFreeRDP" + "Version: %1$s \ n \ u00A9 2012 Technologies GmbH Thinstuff" + "Enregistrer les paramètres de connexion?" + "Vos paramètres de connexion n'ont pas été sauvegardés! Voulez-vous les enregistrer?" + "Enregistrer la connexion?" + "Voulez-vous enregistrer les modifications que vous avez apportées aux paramètres de connexion?" + "Ne plus demander" + "Quittez l'application?" + "Êtes-vous sûr de vouloir quitter l'application?" + "Êtes-vous sûrs de vouloir supprimer les certificats?" + "Êtes-vous sûr de vouloir supprimer tous les certificats mis en cache?" + diff --git a/client/Android/FreeRDPCore/res/xml/application_settings.xml b/client/Android/FreeRDPCore/res/xml/application_settings.xml index 9d7cc0a67..0df4ea126 100644 --- a/client/Android/FreeRDPCore/res/xml/application_settings.xml +++ b/client/Android/FreeRDPCore/res/xml/application_settings.xml @@ -29,5 +29,4 @@ - diff --git a/client/Android/FreeRDPCore/res/xml/bookmark_settings.xml b/client/Android/FreeRDPCore/res/xml/bookmark_settings.xml index c49d4272a..0564537d7 100644 --- a/client/Android/FreeRDPCore/res/xml/bookmark_settings.xml +++ b/client/Android/FreeRDPCore/res/xml/bookmark_settings.xml @@ -12,7 +12,7 @@ - + diff --git a/client/Android/FreeRDPCore/res/xml/credentials_settings.xml b/client/Android/FreeRDPCore/res/xml/credentials_settings.xml index 0247b66cd..a27be58c1 100644 --- a/client/Android/FreeRDPCore/res/xml/credentials_settings.xml +++ b/client/Android/FreeRDPCore/res/xml/credentials_settings.xml @@ -11,8 +11,8 @@ --> - - - + + + diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt index 2183eb9d2..80b03ca62 100644 --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -6,12 +6,10 @@ set(MODULE_PREFIX "FREERDP_CLIENT_MAC") set(FRAMEWORK_HEADERS_PATH /System/Library/Frameworks/Cocoa.framework/Versions/A/Headers/) include_directories(${FRAMEWORK_HEADERS_PATH} /System/Library/Frameworks) - -# set(CMAKE_OSX_SYSROOT MacOSX10.7.sdk) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mmacosx-version-min=10.4") set(GUI_TYPE MACOSX_BUNDLE) -# Import libraries find_library(FOUNDATION_LIBRARY Foundation) find_library(COCOA_LIBRARY Cocoa) find_library(APPKIT_LIBRARY AppKit) @@ -33,16 +31,32 @@ mark_as_advanced(COCOA_LIBRARY FOUNDATION_LIBRARY APPKIT_LIBRARY) set(EXTRA_LIBS ${COCOA_LIBRARY} ${FOUNDATION_LIBRARY} ${APPKIT_LIBRARY}) set(APP_TYPE MACOSX_BUNDLE) -# OS X Interface Builder files -file(GLOB ${MODULE_NAME}_XIBS *.xib) +set(${MODULE_NAME}_XIBS + MainMenu.xib + PasswordDialog.xib) -set(${MODULE_NAME}_RESOURCES ${${MODULE_NAME}_XIBS} ${MACOSX_BUNDLE_ICON_FILE}) +set(${MODULE_NAME}_RESOURCES + ${${MODULE_NAME}_XIBS} + ${MACOSX_BUNDLE_ICON_FILE}) -# Headers -file(GLOB ${MODULE_NAME}_HEADERS *.h) +set(${MODULE_NAME}_HEADERS + AppDelegate.h + MRDPCursor.h + MRDPRailView.h + MRDPRailWindow.h + MRDPView.h + MRDPWindow.h + PasswordDialog.h) -# Source -file(GLOB ${MODULE_NAME}_SOURCES *.m) +set(${MODULE_NAME}_SOURCES + main.m + AppDelegate.m + MRDPCursor.m + MRDPRailView.m + MRDPRailWindow.m + MRDPView.m + MRDPWindow.m + PasswordDialog.m) add_executable(${MODULE_NAME} ${APP_TYPE} @@ -63,13 +77,6 @@ set_target_properties(${MODULE_NAME} PROPERTIES RESOURCE "${${MODULE_NAME}_RESOU # Support for automatic reference counting requires non-fragile abi. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-nonfragile-abi") -# XCode project architecture to native architecture of build machine -# ----------------------------------------------------------------------------------------------------- -# Issue: Had some issues with FreeRDP project building only 64 bit and -# MacFreeRDP attempting to link to both 32 and 64 for dual target. -# In the future the FreeRDP Xcode project should be pulled in for a couple of reasons: -# 1) better step-into debugging 2) automatic dependency compilation and multi-arch compilation + linkage -# If you know the solutions for 1 and 2, please add below. set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_ARCHS "$(NATIVE_ARCH_ACTUAL)") # Set the info plist to the custom instance diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index 678a9b5a1..0f2b26d65 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -37,7 +37,11 @@ set(${MODULE_PREFIX}_SRCS resource.h) if(WITH_CLIENT_INTERFACE) - add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + if(CLIENT_INTERFACE_SHARED) + add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS}) + else() + add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + endif() set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") else() set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} cli/wfreerdp.c cli/wfreerdp.h) diff --git a/client/Windows/wf_event.c b/client/Windows/wf_event.c index a81c9f1ae..c96897fb5 100644 --- a/client/Windows/wf_event.c +++ b/client/Windows/wf_event.c @@ -37,6 +37,9 @@ static HWND g_focus_hWnd; #define X_POS(lParam) (lParam & 0xFFFF) #define Y_POS(lParam) ((lParam >> 16) & 0xFFFF) +BOOL wf_scale_blt(wfInfo* wfi, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1, int y1, DWORD rop); +void wf_scale_mouse_event(wfInfo* wfi, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y); + LRESULT CALLBACK wf_ll_kbd_proc(int nCode, WPARAM wParam, LPARAM lParam) { wfInfo* wfi; @@ -167,6 +170,10 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam switch (Msg) { + case WM_ERASEBKGND: + /* Say we handled it - prevents flickering */ + return (LRESULT) 1; + case WM_PAINT: hdc = BeginPaint(hWnd, &ps); @@ -175,31 +182,29 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam w = ps.rcPaint.right - ps.rcPaint.left + 1; h = ps.rcPaint.bottom - ps.rcPaint.top + 1; - //fprintf(stderr, "WM_PAINT: x:%d y:%d w:%d h:%d\n", x, y, w, h); - - BitBlt(hdc, x, y, w, h, wfi->primary->hdc, x - wfi->offset_x, y - wfi->offset_y, SRCCOPY); + wf_scale_blt(wfi, hdc, x, y, w, h, wfi->primary->hdc, x - wfi->offset_x, y - wfi->offset_y, SRCCOPY); EndPaint(hWnd, &ps); break; case WM_LBUTTONDOWN: - input->MouseEvent(input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); + wf_scale_mouse_event(wfi, input,PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); break; case WM_LBUTTONUP: - input->MouseEvent(input, PTR_FLAGS_BUTTON1, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); + wf_scale_mouse_event(wfi, input, PTR_FLAGS_BUTTON1, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); break; case WM_RBUTTONDOWN: - input->MouseEvent(input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); + wf_scale_mouse_event(wfi, input, PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); break; case WM_RBUTTONUP: - input->MouseEvent(input, PTR_FLAGS_BUTTON2, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); + wf_scale_mouse_event(wfi, input, PTR_FLAGS_BUTTON2, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); break; case WM_MOUSEMOVE: - input->MouseEvent(input, PTR_FLAGS_MOVE, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); + wf_scale_mouse_event(wfi, input, PTR_FLAGS_MOVE, X_POS(lParam) - wfi->offset_x, Y_POS(lParam) - wfi->offset_y); break; case WM_MOUSEWHEEL: @@ -257,3 +262,60 @@ LRESULT CALLBACK wf_event_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam return 0; } + +BOOL wf_scale_blt(wfInfo* wfi, HDC hdc, int x, int y, int w, int h, HDC hdcSrc, int x1, int y1, DWORD rop) +{ + int ww, wh, dw, dh; + + if (!wfi->client_width) + wfi->client_width = wfi->width; + + if (!wfi->client_height) + wfi->client_height = wfi->height; + + ww = wfi->client_width; + wh = wfi->client_height; + dw = wfi->instance->settings->DesktopWidth; + dh = wfi->instance->settings->DesktopHeight; + + if (!ww) + ww = dw; + + if (!wh) + wh = dh; + + if (!wfi->instance->settings->SmartSizing || (ww == dw && wh == dh)) + { + return BitBlt(hdc, x, y, w, h, wfi->primary->hdc, x1, y1, SRCCOPY); + } + else + { + SetStretchBltMode(hdc, HALFTONE); + SetBrushOrgEx(hdc, 0, 0, NULL); + + return StretchBlt(hdc, x * ww / dw, y * wh / dh, ww, wh, wfi->primary->hdc, x1, y1, dw, dh, SRCCOPY); + } + + return TRUE; +} + +void wf_scale_mouse_event(wfInfo* wfi, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) +{ + int ww, wh, dw, dh; + + if (!wfi->client_width) + wfi->client_width = wfi->width; + + if (!wfi->client_height) + wfi->client_height = wfi->height; + + ww = wfi->client_width; + wh = wfi->client_height; + dw = wfi->instance->settings->DesktopWidth; + dh = wfi->instance->settings->DesktopHeight; + + if ((ww == dw) && (wh == dh)) + input->MouseEvent(input, flags, x, y); + else + input->MouseEvent(input, flags, x * dw / ww, y * dh / wh); +} diff --git a/client/Windows/wf_gdi.c b/client/Windows/wf_gdi.c index 39c590f1c..3a15fe26a 100644 --- a/client/Windows/wf_gdi.c +++ b/client/Windows/wf_gdi.c @@ -166,14 +166,54 @@ HBRUSH wf_create_brush(wfInfo * wfi, rdpBrush* brush, UINT32 color, int bpp) return br; } +void wf_scale_rect(wfInfo* wfi, RECT* source) +{ + int ww, wh, dw, dh; + + if (!wfi->client_width) + wfi->client_width = wfi->width; + + if (!wfi->client_height) + wfi->client_height = wfi->height; + + ww = wfi->client_width; + wh = wfi->client_height; + dw = wfi->instance->settings->DesktopWidth; + dh = wfi->instance->settings->DesktopHeight; + + if (!ww) + ww = dw; + + if (!wh) + wh = dh; + + if (wfi->instance->settings->SmartSizing && (ww != dw || wh != dh)) + { + source->bottom = MIN(dh, MAX(0, source->bottom * wh / dh + 2)); + source->top = MIN(dh, MAX(0, source->top * wh / dh - 2)); + source->left = MIN(dw, MAX(0, source->left * ww / dw - 2)); + source->right = MIN(dw, MAX(0, source->right * ww / dw + 2)); + } +} + void wf_invalidate_region(wfInfo* wfi, int x, int y, int width, int height) { + RECT rect; + wfi->update_rect.left = x + wfi->offset_x; wfi->update_rect.top = y + wfi->offset_y; wfi->update_rect.right = wfi->update_rect.left + width; wfi->update_rect.bottom = wfi->update_rect.top + height; + + wf_scale_rect(wfi, &(wfi->update_rect)); InvalidateRect(wfi->hwnd, &(wfi->update_rect), FALSE); - gdi_InvalidateRegion(wfi->hdc, x, y, width, height); + + rect.left = x; + rect.right = width; + rect.top = y; + rect.bottom = height; + wf_scale_rect(wfi, &rect); + gdi_InvalidateRegion(wfi->hdc, rect.left, rect.top, rect.right, rect.bottom); } void wf_update_offset(wfInfo* wfi) diff --git a/client/Windows/wf_interface.c b/client/Windows/wf_interface.c index 055f93591..09c465e88 100644 --- a/client/Windows/wf_interface.c +++ b/client/Windows/wf_interface.c @@ -534,6 +534,8 @@ DWORD WINAPI wf_thread(LPVOID lpParam) int index; int rcount; int wcount; + int width; + int height; BOOL msg_ret; int quit_msg; void* rfds[32]; @@ -626,7 +628,30 @@ DWORD WINAPI wf_thread(LPVOID lpParam) { msg_ret = GetMessage(&msg, NULL, 0, 0); - if (msg_ret == 0 || msg_ret == -1) + if (instance->settings->EmbeddedWindow) + { + if ((msg.message == WM_SETFOCUS) && (msg.lParam == 1)) + { + PostMessage(((wfContext*) instance->context)->wfi->hwnd, WM_SETFOCUS, 0, 0); + } + else if ((msg.message == WM_KILLFOCUS) && (msg.lParam == 1)) + { + PostMessage(((wfContext*) instance->context)->wfi->hwnd, WM_KILLFOCUS, 0, 0); + } + } + + if (msg.message == WM_SIZE) + { + width = LOWORD(msg.lParam); + height = HIWORD(msg.lParam); + + ((wfContext*) instance->context)->wfi->client_width = width; + ((wfContext*) instance->context)->wfi->client_height = height; + + SetWindowPos(((wfContext*) instance->context)->wfi->hwnd, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED); + } + + if ((msg_ret == 0) || (msg_ret == -1)) { quit_msg = TRUE; break; @@ -721,11 +746,9 @@ int freerdp_client_global_uninit() wfInfo* freerdp_client_new(int argc, char** argv) { int index; + int status; wfInfo* wfi; freerdp* instance; - HINSTANCE hInstance; - - hInstance = GetModuleHandle(NULL); instance = freerdp_new(); instance->PreConnect = wf_pre_connect; @@ -745,16 +768,27 @@ wfInfo* freerdp_client_new(int argc, char** argv) wfi->client = instance->context->client; instance->context->argc = argc; - instance->context->argv = argv; - instance->context->argv = (char**) malloc(sizeof(char*) * argc); for (index = 0; index < argc; index++) - { instance->context->argv[index] = _strdup(argv[index]); - } - wfi->hWndParent = NULL; + status = freerdp_client_parse_command_line_arguments(instance->context->argc, instance->context->argv, instance->settings); + + return wfi; +} + +int freerdp_client_start(wfInfo* wfi) +{ + HWND hWndParent; + HINSTANCE hInstance; + freerdp* instance = wfi->instance; + + hInstance = GetModuleHandle(NULL); + hWndParent = (HWND) instance->settings->ParentWindowId; + instance->settings->EmbeddedWindow = (hWndParent) ? TRUE : FALSE; + + wfi->hWndParent = hWndParent; wfi->hInstance = hInstance; wfi->cursor = LoadCursor(NULL, IDC_ARROW); wfi->icon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1)); @@ -774,24 +808,14 @@ wfInfo* freerdp_client_new(int argc, char** argv) wfi->wndClass.hIconSm = wfi->icon; RegisterClassEx(&(wfi->wndClass)); - return wfi; -} - -int freerdp_client_start(wfInfo* wfi) -{ - int status; - freerdp* instance = wfi->instance; - wfi->keyboardThread = CreateThread(NULL, 0, wf_keyboard_thread, (void*) wfi, 0, NULL); if (!wfi->keyboardThread) return -1; - status = freerdp_client_parse_command_line_arguments(instance->context->argc, instance->context->argv, instance->settings); - freerdp_client_load_addins(instance->context->channels, instance->settings); - wfi->thread = CreateThread(NULL, 0, wf_thread, (void*) instance, 0, NULL); + wfi->thread = CreateThread(NULL, 0, wf_thread, (void*) instance, 0, &wfi->mainThreadId); if (!wfi->thread) return -1; @@ -801,6 +825,29 @@ int freerdp_client_start(wfInfo* wfi) int freerdp_client_stop(wfInfo* wfi) { + PostThreadMessage(wfi->mainThreadId, WM_QUIT, 0, 0); + return 0; +} + +int freerdp_client_focus_in(wfInfo* wfi) +{ + PostThreadMessage(wfi->mainThreadId, WM_SETFOCUS, 0, 1); + return 0; +} + +int freerdp_client_focus_out(wfInfo* wfi) +{ + PostThreadMessage(wfi->mainThreadId, WM_KILLFOCUS, 0, 1); + return 0; +} + +int wf_set_window_size(wfInfo* wfi, int width, int height) +{ + if ((width != wfi->client_width) || (height != wfi->client_height)) + { + PostThreadMessage(wfi->mainThreadId, WM_SIZE, SIZE_RESTORED, ((UINT) height << 16) | (UINT) width); + } + return 0; } diff --git a/client/Windows/wf_interface.h b/client/Windows/wf_interface.h index c9f8a3ef3..16891db82 100644 --- a/client/Windows/wf_interface.h +++ b/client/Windows/wf_interface.h @@ -81,6 +81,8 @@ struct wf_info int fullscreen; int percentscreen; char window_title[64]; + int client_width; + int client_height; HANDLE thread; HANDLE keyboardThread; @@ -105,8 +107,10 @@ struct wf_info HBRUSH brush; HBRUSH org_brush; RECT update_rect; + RECT scale_update_rect; wfBitmap* tile; + DWORD mainThreadId; RFX_CONTEXT* rfx_context; NSC_CONTEXT* nsc_context; @@ -125,6 +129,11 @@ FREERDP_API int freerdp_client_global_uninit(); FREERDP_API int freerdp_client_start(wfInfo* cfi); FREERDP_API int freerdp_client_stop(wfInfo* cfi); +FREERDP_API int freerdp_client_focus_in(wfInfo* cfi); +FREERDP_API int freerdp_client_focus_out(wfInfo* cfi); + +FREERDP_API int freerdp_client_set_window_size(wfInfo* cfi, int width, int height); + FREERDP_API cfInfo* freerdp_client_new(int argc, char** argv); FREERDP_API int freerdp_client_free(wfInfo* cfi); diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index 0461a3550..7d08ea670 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -44,7 +44,11 @@ set(${MODULE_PREFIX}_SRCS xf_interface.h) if(WITH_CLIENT_INTERFACE) - add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + if(CLIENT_INTERFACE_SHARED) + add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS}) + else() + add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + endif() set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION} PREFIX "lib") else() set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} cli/xfreerdp.c cli/xfreerdp.h) diff --git a/client/X11/cli/xfreerdp.c b/client/X11/cli/xfreerdp.c index b242c11ee..a2911207e 100644 --- a/client/X11/cli/xfreerdp.c +++ b/client/X11/cli/xfreerdp.c @@ -49,8 +49,7 @@ int main(int argc, char* argv[]) GetExitCodeThread(xfi->thread, &dwExitCode); - freerdp_context_free(instance); - freerdp_free(instance); + freerdp_client_free(xfi); freerdp_client_global_uninit(); diff --git a/client/X11/xf_interface.c b/client/X11/xf_interface.c index c2d6d0a60..3d27a5b49 100644 --- a/client/X11/xf_interface.c +++ b/client/X11/xf_interface.c @@ -1382,9 +1382,6 @@ void* xf_thread(void* param) freerdp_channels_free(channels); freerdp_disconnect(instance); gdi_free(instance); - freerdp_client_free(xfi); - - exit_code = 123; ExitThread(exit_code); } @@ -1475,8 +1472,6 @@ xfInfo* freerdp_client_new(int argc, char** argv) freerdp_context_new(instance); instance->context->argc = argc; - instance->context->argv = argv; - instance->context->argv = (char**) malloc(sizeof(char*) * argc); for (index = 0; index < argc; index++) @@ -1544,12 +1539,25 @@ void freerdp_client_free(xfInfo* xfi) { if (xfi) { + int index; + rdpContext* context; + xf_window_free(xfi); free(xfi->bmp_codec_none); XCloseDisplay(xfi->display); + context = (rdpContext*) xfi->context; + + for (index = 0; index < context->argc; index++) + free(context->argv[index]); + + free(context->argv); + + freerdp_context_free(xfi->instance); + freerdp_free(xfi->instance); + free(xfi); } } diff --git a/client/common/cmdline.c b/client/common/cmdline.c index e2927eb2a..dc5e6a681 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -52,6 +52,7 @@ COMMAND_LINE_ARGUMENT_A args[] = { "workarea", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Work area" }, { "t", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, "title", "Window title" }, { "decorations", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueTrue, -1, NULL, "Window decorations" }, + { "smart-sizing", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Scale remote desktop to window size" }, { "a", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, "addin", "Addin" }, { "vc", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Static virtual channel" }, { "dvc", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Dynamic virtual channel" }, @@ -62,6 +63,7 @@ COMMAND_LINE_ARGUMENT_A args[] = { "gu", COMMAND_LINE_VALUE_REQUIRED, "[<domain>\\]<user> or <user>[@<domain>]", NULL, NULL, -1, NULL, "Gateway username" }, { "gp", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Gateway password" }, { "gd", COMMAND_LINE_VALUE_REQUIRED, "<domain>", NULL, NULL, -1, NULL, "Gateway domain" }, + { "load-balance-info", COMMAND_LINE_VALUE_REQUIRED, "<info string>", NULL, NULL, -1, NULL, "Load balance info" }, { "app", COMMAND_LINE_VALUE_REQUIRED, "||<alias> or <executable path>", NULL, NULL, -1, NULL, "Remote application program" }, { "app-name", COMMAND_LINE_VALUE_REQUIRED, "<app name>", NULL, NULL, -1, NULL, "Remote application name for user interface" }, { "app-icon", COMMAND_LINE_VALUE_REQUIRED, "<icon path>", NULL, NULL, -1, NULL, "Remote application icon for user interface" }, @@ -1090,6 +1092,10 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin { settings->Decorations = arg->Value ? TRUE : FALSE; } + CommandLineSwitchCase(arg, "smart-sizing") + { + settings->SmartSizing = arg->Value ? TRUE : FALSE; + } CommandLineSwitchCase(arg, "bpp") { settings->ColorDepth = atoi(arg->Value); @@ -1209,6 +1215,11 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin settings->DisableWallpaper = TRUE; settings->DisableFullWindowDrag = TRUE; } + CommandLineSwitchCase(arg, "load-balance-info") + { + settings->LoadBalanceInfo = (BYTE*) _strdup(arg->Value); + settings->LoadBalanceInfoLength = strlen((char*) settings->LoadBalanceInfo); + } CommandLineSwitchCase(arg, "app-name") { settings->RemoteApplicationName = _strdup(arg->Value); diff --git a/client/common/file.c b/client/common/file.c index 755aa9391..a13ca239b 100644 --- a/client/common/file.c +++ b/client/common/file.c @@ -308,7 +308,7 @@ BOOL freerdp_client_parse_rdp_file_buffer_ascii(rdpFile* file, BYTE* buffer, siz line = strtok_s((char*) buffer, "\r\n", &context); - while (line != NULL) + while (line) { length = strlen(line); @@ -458,8 +458,7 @@ BOOL freerdp_client_parse_rdp_file(rdpFile* file, char* name) if (file_size < 1) return FALSE; - buffer = (BYTE*) malloc(file_size); - + buffer = (BYTE*) malloc(file_size + 2); read_size = fread(buffer, file_size, 1, fp); if (!read_size) @@ -475,6 +474,9 @@ BOOL freerdp_client_parse_rdp_file(rdpFile* file, char* name) return FALSE; } + buffer[file_size] = '\0'; + buffer[file_size + 1] = '\0'; + return freerdp_client_parse_rdp_file_buffer(file, buffer, file_size); } @@ -497,7 +499,7 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* if (~file->ServerPort) settings->ServerPort = file->ServerPort; if (~((size_t) file->FullAddress)) - settings->ServerHostname = file->FullAddress; + settings->ServerHostname = _strdup(file->FullAddress); if (~file->DesktopWidth) settings->DesktopWidth = file->DesktopWidth; if (~file->DesktopHeight) @@ -513,10 +515,16 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* if (~file->EnableCredSSPSupport) settings->NlaSecurity = file->EnableCredSSPSupport; if (~((size_t) file->AlternateShell)) - settings->AlternateShell = file->AlternateShell; + settings->AlternateShell = _strdup(file->AlternateShell); if (~((size_t) file->ShellWorkingDirectory)) - settings->ShellWorkingDirectory = file->ShellWorkingDirectory; + settings->ShellWorkingDirectory = _strdup(file->ShellWorkingDirectory); + if (~((size_t) file->LoadBalanceInfo)) + { + settings->LoadBalanceInfo = (BYTE*) _strdup(file->LoadBalanceInfo); + settings->LoadBalanceInfoLength = strlen((char*) settings->LoadBalanceInfo); + } + if (~file->ConnectionType) { freerdp_set_connection_type(settings, file->ConnectionType); @@ -540,7 +548,7 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* } if (~((size_t) file->GatewayHostname)) - settings->GatewayHostname = file->GatewayHostname; + settings->GatewayHostname = _strdup(file->GatewayHostname); if (~file->GatewayUsageMethod) settings->GatewayUsageMethod = TRUE; if (~file->PromptCredentialOnce) @@ -549,17 +557,17 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* if (~file->RemoteApplicationMode) settings->RemoteApplicationMode = file->RemoteApplicationMode; if (~((size_t) file->RemoteApplicationProgram)) - settings->RemoteApplicationProgram = file->RemoteApplicationProgram; + settings->RemoteApplicationProgram = _strdup(file->RemoteApplicationProgram); if (~((size_t) file->RemoteApplicationName)) - settings->RemoteApplicationName = file->RemoteApplicationName; + settings->RemoteApplicationName = _strdup(file->RemoteApplicationName); if (~((size_t) file->RemoteApplicationIcon)) - settings->RemoteApplicationIcon = file->RemoteApplicationIcon; + settings->RemoteApplicationIcon = _strdup(file->RemoteApplicationIcon); if (~((size_t) file->RemoteApplicationFile)) - settings->RemoteApplicationFile = file->RemoteApplicationFile; + settings->RemoteApplicationFile = _strdup(file->RemoteApplicationFile); if (~((size_t) file->RemoteApplicationGuid)) - settings->RemoteApplicationGuid = file->RemoteApplicationGuid; + settings->RemoteApplicationGuid = _strdup(file->RemoteApplicationGuid); if (~((size_t) file->RemoteApplicationCmdLine)) - settings->RemoteApplicationCmdLine = file->RemoteApplicationCmdLine; + settings->RemoteApplicationCmdLine = _strdup(file->RemoteApplicationCmdLine); if (~file->SpanMonitors) settings->SpanMonitors = file->SpanMonitors; diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 9a3375c47..0a078c280 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -602,7 +602,11 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_AsyncInput 1544 #define FreeRDP_AsyncUpdate 1545 #define FreeRDP_AsyncChannels 1546 -#define FreeRDP_ToggleFullscreen 1547 +#define FreeRDP_AsyncTransport 1547 +#define FreeRDP_ToggleFullscreen 1548 +#define FreeRDP_WmClass 1549 +#define FreeRDP_EmbeddedWindow 1550 +#define FreeRDP_SmartSizing 1551 #define FreeRDP_SoftwareGdi 1601 #define FreeRDP_LocalConnection 1602 #define FreeRDP_AuthenticationOnly 1603 @@ -961,7 +965,9 @@ struct rdp_settings ALIGN64 BOOL AsyncTransport; /* 1547 */ ALIGN64 BOOL ToggleFullscreen; /* 1548 */ ALIGN64 char* WmClass; /* 1549 */ - UINT64 padding1600[1600 - 1550]; /* 1550 */ + ALIGN64 BOOL EmbeddedWindow; /* 1550 */ + ALIGN64 BOOL SmartSizing; /* 1551 */ + UINT64 padding1600[1600 - 1552]; /* 1552 */ /* Miscellaneous */ ALIGN64 BOOL SoftwareGdi; /* 1601 */ diff --git a/libfreerdp/codec/rfx_decode.c b/libfreerdp/codec/rfx_decode.c index 15aa4cf00..1acffda27 100644 --- a/libfreerdp/codec/rfx_decode.c +++ b/libfreerdp/codec/rfx_decode.c @@ -202,11 +202,12 @@ BOOL rfx_decode_rgb(RFX_CONTEXT* context, wStream* data_in, else #endif { - if (stream_get_left(data_in) < y_size+cb_size+cr_size) + if (stream_get_left(data_in) < y_size + cb_size + cr_size) { DEBUG_WARN("rfx_decode_rgb: packet too small for y_size+cb_size+cr_size"); return FALSE; } + rfx_decode_component(context, y_quants, stream_get_tail(data_in), y_size, pSrcDst[0]); /* YData */ stream_seek(data_in, y_size); @@ -230,5 +231,6 @@ BOOL rfx_decode_rgb(RFX_CONTEXT* context, wStream* data_in, BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[0] - 16); BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[1] - 16); BufferPool_Return(context->priv->BufferPool, (BYTE*)pSrcDst[2] - 16); + return TRUE; } diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index dabba597f..4b60d868b 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -135,6 +135,9 @@ BOOL rdp_client_connect(rdpRdp* rdp) nego_set_cookie_max_length(rdp->nego, settings->CookieMaxLength); + if (settings->LoadBalanceInfo) + nego_set_routing_token(rdp->nego, settings->LoadBalanceInfo, settings->LoadBalanceInfoLength); + if (!nego_connect(rdp->nego)) { fprintf(stderr, "Error: protocol security negotiation or connection failure\n"); diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index 56d06a983..8a680d7e7 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -169,20 +169,21 @@ static BOOL fastpath_recv_update_common(rdpFastPath* fastpath, wStream* s) rdpUpdate* update = fastpath->rdp->update; rdpContext* context = update->context; - if(stream_get_left(s) < 2) + if (stream_get_left(s) < 2) return FALSE; + stream_read_UINT16(s, updateType); /* updateType (2 bytes) */ switch (updateType) { case UPDATE_TYPE_BITMAP: - if(!update_read_bitmap(update, s, &update->bitmap_update)) + if (!update_read_bitmap(update, s, &update->bitmap_update)) return FALSE; IFCALL(update->BitmapUpdate, context, &update->bitmap_update); break; case UPDATE_TYPE_PALETTE: - if(!update_read_palette(update, s, &update->palette_update)) + if (!update_read_palette(update, s, &update->palette_update)) return FALSE; IFCALL(update->Palette, context, &update->palette_update); break; @@ -328,6 +329,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) } update_stream = NULL; + if (fragmentation == FASTPATH_FRAGMENT_SINGLE) { totalSize = size; @@ -340,6 +342,7 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s) stream_check_size(fastpath->updateData, size); stream_copy(fastpath->updateData, comp_stream, size); + if (stream_get_length(fastpath->updateData) > rdp->settings->MultifragMaxRequestSize) { fprintf(stderr, "fastpath PDU is bigger than MultifragMaxRequestSize\n"); diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index b1d05fb82..6770a1ab3 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -340,7 +340,7 @@ void freerdp_context_new(freerdp* instance) */ void freerdp_context_free(freerdp* instance) { - if (instance->context == NULL) + if (!instance->context) return; IFCALL(instance->ContextFree, instance, instance->context); @@ -348,6 +348,8 @@ void freerdp_context_free(freerdp* instance) rdp_free(instance->context->rdp); graphics_free(instance->context->graphics); + free(instance->context->client); + free(instance->context); instance->context = NULL; } diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c index 3e2900b03..3ccea28d3 100644 --- a/libfreerdp/core/message.c +++ b/libfreerdp/core/message.c @@ -21,11 +21,18 @@ #include "config.h" #endif +#include "rdp.h" #include "message.h" +#include "transport.h" + +#include <freerdp/freerdp.h> #include <winpr/crt.h> +#include <winpr/stream.h> #include <winpr/collections.h> +//#define WITH_STREAM_POOL 1 + /* Update */ static void update_message_BeginPaint(rdpContext* context) @@ -79,13 +86,15 @@ static void update_message_BitmapUpdate(rdpContext* context, BITMAP_UPDATE* bitm wParam->rectangles = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * wParam->number); CopyMemory(wParam->rectangles, bitmap->rectangles, sizeof(BITMAP_DATA) * wParam->number); - /* TODO: increment reference count to original stream instead of copying */ - for (index = 0; index < wParam->number; index++) { +#ifdef WITH_STREAM_POOL + StreamPool_AddRef(context->rdp->transport->ReceivePool, bitmap->rectangles[index].bitmapDataStream); +#else wParam->rectangles[index].bitmapDataStream = (BYTE*) malloc(wParam->rectangles[index].bitmapLength); CopyMemory(wParam->rectangles[index].bitmapDataStream, bitmap->rectangles[index].bitmapDataStream, wParam->rectangles[index].bitmapLength); +#endif } MessageQueue_Post(context->update->queue, (void*) context, @@ -160,8 +169,12 @@ static void update_message_SurfaceBits(rdpContext* context, SURFACE_BITS_COMMAND wParam = (SURFACE_BITS_COMMAND*) malloc(sizeof(SURFACE_BITS_COMMAND)); CopyMemory(wParam, surfaceBitsCommand, sizeof(SURFACE_BITS_COMMAND)); +#ifdef WITH_STREAM_POOL + StreamPool_AddRef(context->rdp->transport->ReceivePool, surfaceBitsCommand->bitmapData); +#else wParam->bitmapData = (BYTE*) malloc(wParam->bitmapDataLength); CopyMemory(wParam->bitmapData, surfaceBitsCommand->bitmapData, wParam->bitmapDataLength); +#endif MessageQueue_Post(context->update->queue, (void*) context, MakeMessageId(Update, SurfaceBits), (void*) wParam, NULL); @@ -952,7 +965,14 @@ int update_message_process_update_class(rdpUpdateProxy* proxy, wMessage* msg, in BITMAP_UPDATE* wParam = (BITMAP_UPDATE*) msg->wParam; for (index = 0; index < wParam->number; index++) + { +#ifdef WITH_STREAM_POOL + rdpContext* context = (rdpContext*) msg->context; + StreamPool_Release(context->rdp->transport->ReceivePool, wParam->rectangles[index].bitmapDataStream); +#else free(wParam->rectangles[index].bitmapDataStream); +#endif + } free(wParam); } @@ -993,9 +1013,15 @@ int update_message_process_update_class(rdpUpdateProxy* proxy, wMessage* msg, in case Update_SurfaceBits: IFCALL(proxy->SurfaceBits, msg->context, (SURFACE_BITS_COMMAND*) msg->wParam); { +#ifdef WITH_STREAM_POOL + rdpContext* context = (rdpContext*) msg->context; + SURFACE_BITS_COMMAND* wParam = (SURFACE_BITS_COMMAND*) msg->wParam; + StreamPool_Release(context->rdp->transport->ReceivePool, wParam->bitmapData); +#else SURFACE_BITS_COMMAND* wParam = (SURFACE_BITS_COMMAND*) msg->wParam; free(wParam->bitmapData); free(wParam); +#endif } break; diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 6ee58d9b7..0227620ae 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -490,7 +490,7 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra) if (length == 0) return -1; - if(!tpdu_read_connection_confirm(s, &li)) + if (!tpdu_read_connection_confirm(s, &li)) return -1; if (li > 6) @@ -563,7 +563,8 @@ BOOL nego_read_request(rdpNego* nego, wStream* s) BYTE type; tpkt_read_header(s); - if(!tpdu_read_connection_request(s, &li)) + + if (!tpdu_read_connection_request(s, &li)) return FALSE; if (li != stream_get_left(s) + 6) @@ -648,12 +649,14 @@ BOOL nego_send_negotiation_request(rdpNego* nego) stream_get_mark(s, bm); stream_seek(s, length); - if (nego->RoutingToken != NULL) + if (nego->RoutingToken) { stream_write(s, nego->RoutingToken, nego->RoutingTokenLength); - length += nego->RoutingTokenLength; + stream_write_BYTE(s, 0x0D); /* CR */ + stream_write_BYTE(s, 0x0A); /* LF */ + length += nego->RoutingTokenLength + 2; } - else if (nego->cookie != NULL) + else if (nego->cookie) { cookie_length = strlen(nego->cookie); @@ -669,7 +672,7 @@ BOOL nego_send_negotiation_request(rdpNego* nego) DEBUG_NEGO("requested_protocols: %d", nego->requested_protocols); - if (nego->requested_protocols > PROTOCOL_RDP) + if ((nego->requested_protocols > PROTOCOL_RDP) || (nego->sendNegoData)) { /* RDP_NEG_DATA must be present for TLS and NLA */ stream_write_BYTE(s, TYPE_RDP_NEG_REQ); @@ -762,18 +765,24 @@ void nego_process_negotiation_failure(rdpNego* nego, wStream* s) case SSL_REQUIRED_BY_SERVER: DEBUG_NEGO("Error: SSL_REQUIRED_BY_SERVER"); break; + case SSL_NOT_ALLOWED_BY_SERVER: DEBUG_NEGO("Error: SSL_NOT_ALLOWED_BY_SERVER"); break; + case SSL_CERT_NOT_ON_SERVER: DEBUG_NEGO("Error: SSL_CERT_NOT_ON_SERVER"); + nego->sendNegoData = TRUE; break; + case INCONSISTENT_FLAGS: DEBUG_NEGO("Error: INCONSISTENT_FLAGS"); break; + case HYBRID_REQUIRED_BY_SERVER: DEBUG_NEGO("Error: HYBRID_REQUIRED_BY_SERVER"); break; + default: DEBUG_NEGO("Error: Unknown protocol security error %d", failureCode); break; diff --git a/libfreerdp/core/nego.h b/libfreerdp/core/nego.h index 48e3d0410..e8f429fb8 100644 --- a/libfreerdp/core/nego.h +++ b/libfreerdp/core/nego.h @@ -100,6 +100,7 @@ struct rdp_nego BOOL security_connected; UINT32 cookie_max_length; + BOOL sendNegoData; UINT32 selected_protocol; UINT32 requested_protocols; BOOL NegotiateSecurityLayer; diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index c44ae9667..8411b4b88 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -454,6 +454,7 @@ void freerdp_settings_free(rdpSettings* settings) free(settings->ConfigPath); free(settings->CurrentPath); free(settings->HomePath); + free(settings->LoadBalanceInfo); freerdp_device_collection_free(settings); freerdp_static_channel_collection_free(settings); freerdp_dynamic_channel_collection_free(settings); diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c index 1c961f5d9..42d39f1ab 100644 --- a/libfreerdp/core/surface.c +++ b/libfreerdp/core/surface.c @@ -25,7 +25,7 @@ #include "surface.h" -static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT32 *length) +static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT32* length) { int pos; SURFACE_BITS_COMMAND* cmd = &update->surface_bits_command; @@ -50,11 +50,11 @@ static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT3 pos = stream_get_pos(s) + cmd->bitmapDataLength; cmd->bitmapData = stream_get_tail(s); - IFCALL(update->SurfaceBits, update->context, cmd); - stream_set_pos(s, pos); *length = 20 + cmd->bitmapDataLength; + IFCALL(update->SurfaceBits, update->context, cmd); + return 0; } diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 29f8e6297..c1033e225 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -703,8 +703,7 @@ int transport_check_fds(rdpTransport** ptransport) } received = transport->ReceiveBuffer; - transport->ReceiveBuffer = ObjectPool_Take(transport->ReceivePool); - transport->ReceiveBuffer->pointer = transport->ReceiveBuffer->buffer; + transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); stream_set_pos(received, length); stream_seal(received); @@ -720,7 +719,7 @@ int transport_check_fds(rdpTransport** ptransport) recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); - ObjectPool_Return(transport->ReceivePool, received); + Stream_Release(received); if (recv_status < 0) status = -1; @@ -799,16 +798,6 @@ static void* transport_client_thread(void* arg) return NULL; } -wStream* transport_receive_buffer_pool_new() -{ - wStream* pdu = NULL; - - pdu = stream_new(BUFFER_SIZE); - pdu->pointer = pdu->buffer; - - return pdu; -} - rdpTransport* transport_new(rdpSettings* settings) { rdpTransport* transport; @@ -826,16 +815,14 @@ rdpTransport* transport_new(rdpSettings* settings) /* a small 0.1ms delay when transport is blocking. */ transport->SleepInterval = 100; - transport->ReceivePool = ObjectPool_New(TRUE); - ObjectPool_Object(transport->ReceivePool)->fnObjectFree = (OBJECT_FREE_FN) stream_free; - ObjectPool_Object(transport->ReceivePool)->fnObjectNew = (OBJECT_NEW_FN) transport_receive_buffer_pool_new; + transport->ReceivePool = StreamPool_New(TRUE, BUFFER_SIZE); /* receive buffer for non-blocking read. */ - transport->ReceiveBuffer = ObjectPool_Take(transport->ReceivePool); + transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0); transport->ReceiveEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* buffers for blocking read/write */ - transport->ReceiveStream = stream_new(BUFFER_SIZE); + transport->ReceiveStream = StreamPool_Take(transport->ReceivePool, 0); transport->SendStream = stream_new(BUFFER_SIZE); transport->blocking = TRUE; @@ -851,11 +838,13 @@ void transport_free(rdpTransport* transport) if (transport != NULL) { if (transport->ReceiveBuffer) - ObjectPool_Return(transport->ReceivePool, transport->ReceiveBuffer); + Stream_Release(transport->ReceiveBuffer); - ObjectPool_Free(transport->ReceivePool); + if (transport->ReceiveStream) + Stream_Release(transport->ReceiveStream); + + StreamPool_Free(transport->ReceivePool); - stream_free(transport->ReceiveStream); stream_free(transport->SendStream); CloseHandle(transport->ReceiveEvent); diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h index 0dc04122a..67a2e2783 100644 --- a/libfreerdp/core/transport.h +++ b/libfreerdp/core/transport.h @@ -69,7 +69,7 @@ struct rdp_transport HANDLE GatewayEvent; BOOL blocking; BOOL SplitInputOutput; - wObjectPool* ReceivePool; + wStreamPool* ReceivePool; HANDLE stopEvent; HANDLE thread; BOOL async; diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h index 32b412529..521e8578e 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -28,6 +28,7 @@ #include <winpr/wtypes.h> #include <winpr/synch.h> +#include <winpr/stream.h> typedef void* (*OBJECT_NEW_FN)(void); typedef void (*OBJECT_FREE_FN)(void* obj); diff --git a/winpr/include/winpr/stream.h b/winpr/include/winpr/stream.h index 3c0924eb0..6910734a0 100644 --- a/winpr/include/winpr/stream.h +++ b/winpr/include/winpr/stream.h @@ -28,12 +28,17 @@ extern "C" { #endif +typedef struct _wStreamPool wStreamPool; + struct _wStream { BYTE* buffer; BYTE* pointer; size_t length; size_t capacity; + + DWORD count; + wStreamPool* pool; }; typedef struct _wStream wStream; @@ -337,6 +342,38 @@ static INLINE BOOL stream_skip(wStream* s, int sz) { return TRUE; } +/* StreamPool */ + +struct _wStreamPool +{ + int aSize; + int aCapacity; + wStream** aArray; + + int uSize; + int uCapacity; + wStream** uArray; + + HANDLE mutex; + BOOL synchronized; + size_t defaultSize; +}; + +WINPR_API wStream* StreamPool_Take(wStreamPool* pool, size_t size); +WINPR_API void StreamPool_Return(wStreamPool* pool, wStream* s); + +WINPR_API void Stream_AddRef(wStream* s); +WINPR_API void Stream_Release(wStream* s); + +WINPR_API wStream* StreamPool_Find(wStreamPool* pool, BYTE* ptr); +WINPR_API void StreamPool_AddRef(wStreamPool* pool, BYTE* ptr); +WINPR_API void StreamPool_Release(wStreamPool* pool, BYTE* ptr); + +WINPR_API void StreamPool_Clear(wStreamPool* pool); + +WINPR_API wStreamPool* StreamPool_New(BOOL synchronized, size_t defaultSize); +WINPR_API void StreamPool_Free(wStreamPool* pool); + #ifdef __cplusplus } #endif diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index 6bcae3eee..8cb2466f0 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -25,6 +25,10 @@ #include <winpr/winpr.h> #include <winpr/wtypes.h> +#ifdef __cplusplus +extern "C" { +#endif + #ifndef _WIN32 #define CSTR_LESS_THAN 1 @@ -174,4 +178,8 @@ WINPR_API int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteS WINPR_API int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar); +#ifdef __cplusplus +} +#endif + #endif /* WINPR_CRT_STRING_H */ diff --git a/winpr/libwinpr/interlocked/interlocked.c b/winpr/libwinpr/interlocked/interlocked.c index 9065376d3..044c36684 100644 --- a/winpr/libwinpr/interlocked/interlocked.c +++ b/winpr/libwinpr/interlocked/interlocked.c @@ -236,7 +236,11 @@ LONG InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG #endif /* _WIN32 */ -#if (_WIN32 && (_WIN32_WINNT < 0x0502)) +#if defined(_WIN64) + +/* InterlockedCompareExchange64 already defined */ + +#elif (_WIN32 && (_WIN32_WINNT < 0x0502)) static volatile HANDLE mutex = NULL; diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index d3f210838..50c6eaad7 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -29,6 +29,7 @@ set(${MODULE_PREFIX}_COLLECTIONS_SRCS collections/CountdownEvent.c collections/BufferPool.c collections/ObjectPool.c + collections/StreamPool.c collections/MessageQueue.c collections/MessagePipe.c) diff --git a/winpr/libwinpr/utils/collections/StreamPool.c b/winpr/libwinpr/utils/collections/StreamPool.c new file mode 100644 index 000000000..96a491acf --- /dev/null +++ b/winpr/libwinpr/utils/collections/StreamPool.c @@ -0,0 +1,323 @@ +/** + * WinPR: Windows Portable Runtime + * Object Pool + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <winpr/crt.h> + +#include <winpr/collections.h> + +/** + * Methods + */ + +void StreamPool_ShiftUsed(wStreamPool* pool, int index, int count) +{ + if (count > 0) + { + if (pool->uSize + count > pool->uCapacity) + { + pool->uCapacity *= 2; + pool->uArray = (wStream**) realloc(pool->uArray, sizeof(wStream*) * pool->uCapacity); + } + + MoveMemory(&pool->uArray[index + count], &pool->uArray[index], (pool->uSize - index) * sizeof(wStream*)); + pool->uSize += count; + } + else if (count < 0) + { + MoveMemory(&pool->uArray[index], &pool->uArray[index - count], (pool->uSize + count) * sizeof(wStream*)); + pool->uSize += count; + } +} + +/** + * Adds a used stream to the pool. + */ + +void StreamPool_AddUsed(wStreamPool* pool, wStream* s) +{ + int index; + + if ((pool->uSize + 1) >= pool->uCapacity) + { + pool->uCapacity *= 2; + pool->uArray = (wStream**) realloc(pool->uArray, sizeof(wStream*) * pool->uCapacity); + } + + pool->uArray[(pool->uSize)++] = s; +} + +/** + * Removes a used stream from the pool. + */ + +void StreamPool_RemoveUsed(wStreamPool* pool, wStream* s) +{ + int index; + BOOL found = FALSE; + + for (index = 0; index < pool->uSize; index++) + { + if (pool->uArray[index] == s) + { + found = TRUE; + break; + } + } + + if (found) + StreamPool_ShiftUsed(pool, index, -1); +} + +/** + * Gets a stream from the pool. + */ + +wStream* StreamPool_Take(wStreamPool* pool, size_t size) +{ + wStream* s = NULL; + + if (pool->synchronized) + WaitForSingleObject(pool->mutex, INFINITE); + + if (pool->aSize > 0) + s = pool->aArray[--(pool->aSize)]; + + if (size == 0) + size = pool->defaultSize; + + if (!s) + { + s = Stream_New(NULL, size); + } + else + { + Stream_EnsureCapacity(s, size); + Stream_Pointer(s) = Stream_Buffer(s); + } + + s->pool = pool; + s->count = 1; + + StreamPool_AddUsed(pool, s); + + if (pool->synchronized) + ReleaseMutex(pool->mutex); + + return s; +} + +/** + * Returns an object to the pool. + */ + +void StreamPool_Return(wStreamPool* pool, wStream* s) +{ + if (pool->synchronized) + WaitForSingleObject(pool->mutex, INFINITE); + + if ((pool->aSize + 1) >= pool->aCapacity) + { + pool->aCapacity *= 2; + pool->aArray = (wStream**) realloc(pool->aArray, sizeof(wStream*) * pool->aCapacity); + } + + pool->aArray[(pool->aSize)++] = s; + StreamPool_RemoveUsed(pool, s); + + if (pool->synchronized) + ReleaseMutex(pool->mutex); +} + +/** + * Lock the stream pool + */ + +void StreamPool_Lock(wStreamPool* pool) +{ + WaitForSingleObject(pool->mutex, INFINITE); +} + +/** + * Unlock the stream pool + */ + +void StreamPool_Unlock(wStreamPool* pool) +{ + ReleaseMutex(pool->mutex); +} + +/** + * Increment stream reference count + */ + +void Stream_AddRef(wStream* s) +{ + if (s->pool) + { + StreamPool_Lock(s->pool); + s->count++; + StreamPool_Unlock(s->pool); + } +} + +/** + * Decrement stream reference count + */ + +void Stream_Release(wStream* s) +{ + DWORD count; + + if (s->pool) + { + StreamPool_Lock(s->pool); + count = --(s->count); + StreamPool_Unlock(s->pool); + + if (count == 0) + StreamPool_Return(s->pool, s); + } +} + +/** + * Find stream in pool using pointer inside buffer + */ + +wStream* StreamPool_Find(wStreamPool* pool, BYTE* ptr) +{ + int index; + wStream* s = NULL; + BOOL found = FALSE; + + WaitForSingleObject(pool->mutex, INFINITE); + + for (index = 0; index < pool->uSize; index++) + { + s = pool->uArray[index]; + + if ((ptr >= s->buffer) && (ptr < (s->buffer + s->capacity))) + { + found = TRUE; + break; + } + } + + ReleaseMutex(pool->mutex); + + return (found) ? s : NULL; +} + +/** + * Find stream in pool and increment reference count + */ + +void StreamPool_AddRef(wStreamPool* pool, BYTE* ptr) +{ + wStream* s; + + s = StreamPool_Find(pool, ptr); + + if (s) + Stream_AddRef(s); +} + +/** + * Find stream in pool and decrement reference count + */ + +void StreamPool_Release(wStreamPool* pool, BYTE* ptr) +{ + wStream* s; + + s = StreamPool_Find(pool, ptr); + + if (s) + Stream_Release(s); +} + +/** + * Releases the streams currently cached in the pool. + */ + +void StreamPool_Clear(wStreamPool* pool) +{ + if (pool->synchronized) + WaitForSingleObject(pool->mutex, INFINITE); + + while (pool->aSize > 0) + { + (pool->aSize)--; + Stream_Free(pool->aArray[pool->aSize], TRUE); + } + + if (pool->synchronized) + ReleaseMutex(pool->mutex); +} + +/** + * Construction, Destruction + */ + +wStreamPool* StreamPool_New(BOOL synchronized, size_t defaultSize) +{ + wStreamPool* pool = NULL; + + pool = (wStreamPool*) malloc(sizeof(wStreamPool)); + + if (pool) + { + ZeroMemory(pool, sizeof(wStreamPool)); + + pool->synchronized = synchronized; + pool->defaultSize = defaultSize; + + if (pool->synchronized) + pool->mutex = CreateMutex(NULL, FALSE, NULL); + + pool->aSize = 0; + pool->aCapacity = 32; + pool->aArray = (wStream**) malloc(sizeof(wStream*) * pool->aCapacity); + + pool->uSize = 0; + pool->uCapacity = 32; + pool->uArray = (wStream**) malloc(sizeof(wStream*) * pool->uCapacity); + } + + return pool; +} + +void StreamPool_Free(wStreamPool* pool) +{ + if (pool) + { + StreamPool_Clear(pool); + + if (pool->synchronized) + CloseHandle(pool->mutex); + + free(pool->aArray); + free(pool->uArray); + + free(pool); + } +} diff --git a/winpr/libwinpr/utils/test/CMakeLists.txt b/winpr/libwinpr/utils/test/CMakeLists.txt index cf967be4b..307aae204 100644 --- a/winpr/libwinpr/utils/test/CMakeLists.txt +++ b/winpr/libwinpr/utils/test/CMakeLists.txt @@ -9,6 +9,7 @@ set(${MODULE_PREFIX}_TESTS TestPrint.c TestArrayList.c TestCmdLine.c + TestStreamPool.c TestMessageQueue.c TestMessagePipe.c) diff --git a/winpr/libwinpr/utils/test/TestStreamPool.c b/winpr/libwinpr/utils/test/TestStreamPool.c new file mode 100644 index 000000000..ab8a371e4 --- /dev/null +++ b/winpr/libwinpr/utils/test/TestStreamPool.c @@ -0,0 +1,101 @@ + +#include <winpr/crt.h> +#include <winpr/stream.h> +#include <winpr/collections.h> + +#define BUFFER_SIZE 16384 + +int TestStreamPool(int argc, char* argv[]) +{ + wStream* s[5]; + wStreamPool* pool; + + pool = StreamPool_New(TRUE, BUFFER_SIZE); + + s[0] = StreamPool_Take(pool, 0); + s[1] = StreamPool_Take(pool, 0); + s[2] = StreamPool_Take(pool, 0); + + printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize); + + Stream_Release(s[0]); + Stream_Release(s[1]); + Stream_Release(s[2]); + + printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize); + + s[3] = StreamPool_Take(pool, 0); + s[4] = StreamPool_Take(pool, 0); + + printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize); + + Stream_Release(s[3]); + Stream_Release(s[4]); + + printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize); + + s[2] = StreamPool_Take(pool, 0); + s[3] = StreamPool_Take(pool, 0); + s[4] = StreamPool_Take(pool, 0); + + printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize); + + Stream_AddRef(s[2]); + + Stream_AddRef(s[3]); + Stream_AddRef(s[3]); + + Stream_AddRef(s[4]); + Stream_AddRef(s[4]); + Stream_AddRef(s[4]); + + Stream_Release(s[2]); + Stream_Release(s[2]); + + Stream_Release(s[3]); + Stream_Release(s[3]); + Stream_Release(s[3]); + + Stream_Release(s[4]); + Stream_Release(s[4]); + Stream_Release(s[4]); + Stream_Release(s[4]); + + printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize); + + s[2] = StreamPool_Take(pool, 0); + s[3] = StreamPool_Take(pool, 0); + s[4] = StreamPool_Take(pool, 0); + + printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize); + + StreamPool_AddRef(pool, s[2]->buffer + 1024); + + StreamPool_AddRef(pool, s[3]->buffer + 1024); + StreamPool_AddRef(pool, s[3]->buffer + 1024 * 2); + + StreamPool_AddRef(pool, s[4]->buffer + 1024); + StreamPool_AddRef(pool, s[4]->buffer + 1024 * 2); + StreamPool_AddRef(pool, s[4]->buffer + 1024 * 3); + + printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize); + + StreamPool_Release(pool, s[2]->buffer + 2048); + StreamPool_Release(pool, s[2]->buffer + 2048 * 2); + + StreamPool_Release(pool, s[3]->buffer + 2048); + StreamPool_Release(pool, s[3]->buffer + 2048 * 2); + StreamPool_Release(pool, s[3]->buffer + 2048 * 3); + + StreamPool_Release(pool, s[4]->buffer + 2048); + StreamPool_Release(pool, s[4]->buffer + 2048 * 2); + StreamPool_Release(pool, s[4]->buffer + 2048 * 3); + StreamPool_Release(pool, s[4]->buffer + 2048 * 4); + + printf("StreamPool: aSize: %d uSize: %d\n", pool->aSize, pool->uSize); + + StreamPool_Free(pool); + + return 0; +} +