diff --git a/.gitignore b/.gitignore index 048417b7d..ff66464d9 100755 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,9 @@ external/* # Documentation docs/api client/X11/xfreerdp.1 +client/X11/xfreerdp.1.xml +client/X11/xfreerdp-channels.1.xml +client/X11/xfreerdp-examples.1.xml # Mac OS X .DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index edd2e0aa5..a38dd3a19 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,7 +142,7 @@ if(CMAKE_COMPILER_IS_GNUCC) endif() endif() if(CMAKE_BUILD_TYPE STREQUAL "Release") - set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG") + set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") else() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") @@ -160,10 +160,10 @@ endif() if(MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Gd") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MT") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ob2") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W2") + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MD") + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /O2") + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Ob2") + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W2") if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_AMD64_") else() @@ -171,6 +171,13 @@ if(MSVC) endif() SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}) SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) + + if(CMAKE_BUILD_TYPE STREQUAL "Release") + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Zi") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi") + endif() + endif() if(WIN32) @@ -220,21 +227,24 @@ if(APPLE) set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${FREERDP_IOS_EXTERNAL_SSL_PATH}) set_property(GLOBAL PROPERTY XCODE_ATTRIBUTE_SKIP_INSTALL YES) else() + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6) + + if(NOT DEFINED CMAKE_OSX_ARCHITECTURES) + set(CMAKE_OSX_ARCHITECTURES i386 x86_64) + endif() + if(IS_DIRECTORY /opt/local/include) include_directories(/opt/local/include) link_directories(/opt/local/lib) endif() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.5") endif() + if(WITH_CLANG) set(CMAKE_C_COMPILER "clang") endif() if (WITH_VERBOSE) - # Support for automatic reference counting requires non-fragile abi. set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -v") - - # Tell the compiler where to look for the FreeRDP framework set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -v") endif() endif() @@ -261,6 +271,7 @@ endif() if(UNIX OR CYGWIN) check_include_files(sys/eventfd.h HAVE_EVENTFD_H) + check_include_files(sys/timerfd.h HAVE_TIMERFD_H) set(X11_FEATURE_TYPE "RECOMMENDED") else() set(X11_FEATURE_TYPE "DISABLED") @@ -313,6 +324,10 @@ set(NPP_FEATURE_TYPE "OPTIONAL") set(NPP_FEATURE_PURPOSE "performance") set(NPP_FEATURE_DESCRIPTION "NVIDIA Performance Primitives library") +set(JPEG_FEATURE_TYPE "OPTIONAL") +set(JPEG_FEATURE_PURPOSE "codec") +set(JPEG_FEATURE_DESCRIPTION "use JPEG library") + if(WIN32) set(X11_FEATURE_TYPE "DISABLED") set(ZLIB_FEATURE_TYPE "DISABLED") @@ -329,8 +344,9 @@ if(APPLE) set(DIRECTFB_FEATURE_TYPE "DISABLED") set(FFMPEG_FEATURE_TYPE "OPTIONAL") set(GSTREAMER_FEATURE_TYPE "OPTIONAL") - set(X11_FEATURE_TYPE "DISABLED") + set(X11_FEATURE_TYPE "OPTIONAL") if(IOS) + set(X11_FEATURE_TYPE "DISABLED") set(ALSA_FEATURE_TYPE "DISABLED") set(PULSE_FEATURE_TYPE "DISABLED") set(CUPS_FEATURE_TYPE "DISABLED") @@ -353,6 +369,11 @@ endif() find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION}) find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION}) +if (${WITH_DIRECTFB}) + message(WARNING " +DIRECTFB is orphaned and not maintained see docs/README.directfb for details +") +endif() find_feature(ZLIB ${ZLIB_FEATURE_TYPE} ${ZLIB_FEATURE_PURPOSE} ${ZLIB_FEATURE_DESCRIPTION}) find_feature(OpenSSL ${OPENSSL_FEATURE_TYPE} ${OPENSSL_FEATURE_PURPOSE} ${OPENSSL_FEATURE_DESCRIPTION}) @@ -366,6 +387,8 @@ find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DE find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION}) find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION}) +find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) + if(TARGET_ARCH MATCHES "x86|x64") if (NOT APPLE) # Intel Performance Primitives @@ -394,12 +417,12 @@ set(FREERDP_ADDIN_PATH "${FREERDP_PLUGIN_PATH}") set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp/extensions") # Include directories -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) # Configure files add_definitions("-DHAVE_CONFIG_H") -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/config.h) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) # RPATH configuration set(CMAKE_SKIP_BUILD_RPATH FALSE) @@ -424,8 +447,8 @@ if(BUILD_TESTING) endif() # WinPR -set(WINPR_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/winpr/include") -include_directories(${WINPR_INCLUDE_DIR}) +include_directories("${CMAKE_SOURCE_DIR}/winpr/include") +include_directories("${CMAKE_BINARY_DIR}/winpr/include") add_subdirectory(winpr) @@ -449,7 +472,9 @@ if(WITH_THIRD_PARTY) endif() endif() -add_subdirectory(include) +if (NOT WITH_WAYK) + add_subdirectory(include) +endif() add_subdirectory(libfreerdp) @@ -474,6 +499,8 @@ endif() SET(CPACK_BINARY_ZIP "ON") +if(NOT WITH_WAYK) + set(CPACK_SOURCE_IGNORE_FILES "/\\\\.git/;/\\\\.gitignore;/CMakeCache.txt") if(NOT WIN32) @@ -529,9 +556,12 @@ if(MSVC) if(MSVC_RUNTIME STREQUAL "dynamic") set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE) include(InstallRequiredSystemLibraries) + +if(NOT WITH_WAYK) install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libraries) +endif() endif() set(EXTRA_DATA_DIR "extra/") @@ -577,3 +607,4 @@ endif() include(CPack) +endif() diff --git a/buildx/client/Mac/cli/Info.plist b/buildx/client/Mac/cli/Info.plist deleted file mode 100644 index cb6976502..000000000 --- a/buildx/client/Mac/cli/Info.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - - CFBundleIconFile - FreeRDP - CFBundleIdentifier - FreeRDP.Mac - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - LSMinimumSystemVersion - - NSHumanReadableCopyright - Copyright © 2012 __MyCompanyName__. All rights reserved. - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/channels/audin/client/pulse/audin_pulse.c b/channels/audin/client/pulse/audin_pulse.c index 2d4906ea2..787f208bd 100644 --- a/channels/audin/client/pulse/audin_pulse.c +++ b/channels/audin/client/pulse/audin_pulse.c @@ -290,6 +290,17 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length BYTE* encoded_data; AudinPulseDevice* pulse = (AudinPulseDevice*) userdata; + /* There is a race condition here where we may receive this callback + * before the buffer has been set up in the main code. It's probably + * possible to fix with additional locking, but it's easier just to + * ignore input until the buffer is ready. + */ + if (pulse->buffer == NULL) + { + /* fprintf(stderr, "%s: ignoring input, pulse buffer not ready.\n", __func__); */ + return; + } + pa_stream_peek(stream, &data, &length); frames = length / pulse->bytes_per_frame; @@ -373,6 +384,7 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u DEBUG_DVC(""); + pulse->buffer = NULL; pulse->receive = receive; pulse->user_data = user_data; diff --git a/channels/client/CMakeLists.txt b/channels/client/CMakeLists.txt index 6aa60777a..fc42466bb 100644 --- a/channels/client/CMakeLists.txt +++ b/channels/client/CMakeLists.txt @@ -19,16 +19,16 @@ set(MODULE_NAME "freerdp-channels-client") set(MODULE_PREFIX "FREERDP_CHANNELS_CLIENT") set(${MODULE_PREFIX}_SRCS - tables.c - tables.h - addin.c - addin.h - init.c - init.h - open.c - open.h - channels.c - channels.h) + ${CMAKE_CURRENT_BINARY_DIR}/tables.c + ${CMAKE_CURRENT_SOURCE_DIR}/tables.h + ${CMAKE_CURRENT_SOURCE_DIR}/addin.c + ${CMAKE_CURRENT_SOURCE_DIR}/addin.h + ${CMAKE_CURRENT_SOURCE_DIR}/init.c + ${CMAKE_CURRENT_SOURCE_DIR}/init.h + ${CMAKE_CURRENT_SOURCE_DIR}/open.c + ${CMAKE_CURRENT_SOURCE_DIR}/open.h + ${CMAKE_CURRENT_SOURCE_DIR}/channels.c + ${CMAKE_CURRENT_SOURCE_DIR}/channels.h) list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES) @@ -96,7 +96,7 @@ foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES}) endforeach() set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NULL }\n};") -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_SOURCE_DIR}/tables.c) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_BINARY_DIR}/tables.c) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} diff --git a/channels/client/channels.c b/channels/client/channels.c index a9ea2b0dc..bf886dba4 100644 --- a/channels/client/channels.c +++ b/channels/client/channels.c @@ -441,10 +441,14 @@ int freerdp_channels_load_plugin(rdpChannels* channels, rdpSettings* settings, c int freerdp_drdynvc_on_channel_connected(DrdynvcClientContext* context, const char* name, void* pInterface) { int status = 0; + ChannelConnectedEventArgs e; rdpChannels* channels = (rdpChannels*) context->custom; freerdp* instance = channels->instance; - IFCALLRET(instance->OnChannelConnected, status, instance, name, pInterface); + EventArgsInit(&e, "freerdp"); + e.name = name; + e.pInterface = pInterface; + PubSub_OnChannelConnected(instance->context->pubSub, instance->context, &e); return status; } @@ -452,10 +456,14 @@ int freerdp_drdynvc_on_channel_connected(DrdynvcClientContext* context, const ch int freerdp_drdynvc_on_channel_disconnected(DrdynvcClientContext* context, const char* name, void* pInterface) { int status = 0; + ChannelDisconnectedEventArgs e; rdpChannels* channels = (rdpChannels*) context->custom; freerdp* instance = channels->instance; - IFCALLRET(instance->OnChannelDisconnected, status, instance, name, pInterface); + EventArgsInit(&e, "freerdp"); + e.name = name; + e.pInterface = pInterface; + PubSub_OnChannelDisconnected(instance->context->pubSub, instance->context, &e); return status; } diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index 023bbf8e1..426475a64 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -87,14 +87,15 @@ void cliprdr_process_format_list_event(cliprdrPlugin* cliprdr, RDP_CB_FORMAT_LIS if (!cliprdr->use_long_format_names) name_length = 32; - Stream_EnsureRemainingCapacity(body, Stream_Capacity(body) + 4 + name_length); + Stream_EnsureRemainingCapacity(body, 4 + name_length); Stream_Write_UINT32(body, cb_event->formats[i]); Stream_Write(body, name, name_length); } - s = cliprdr_packet_new(CB_FORMAT_LIST, 0, Stream_Capacity(body)); - Stream_Write(s, Stream_Buffer(body), Stream_Capacity(body)); + Stream_SealLength(body); + s = cliprdr_packet_new(CB_FORMAT_LIST, 0, Stream_Length(body)); + Stream_Write(s, Stream_Buffer(body), Stream_Length(body)); Stream_Free(body, TRUE); } @@ -290,16 +291,16 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data void cliprdr_process_format_list_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) { - /* where is this documented? */ -#if 0 + /* http://msdn.microsoft.com/en-us/library/hh872154.aspx */ wMessage* event; if ((msgFlags & CB_RESPONSE_FAIL) != 0) { - event = freerdp_event_new(RDP_EVENT_CLASS_CLIPRDR, RDP_EVENT_TYPE_CB_MONITOR_READY, NULL, NULL); + /* In case of an error the clipboard will not be synchronized with the server. + * Post this event to restart format negociation and data transfer. */ + event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL); svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event); } -#endif } void cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) diff --git a/channels/disp/CMakeLists.txt b/channels/disp/CMakeLists.txt new file mode 100644 index 000000000..541892d95 --- /dev/null +++ b/channels/disp/CMakeLists.txt @@ -0,0 +1,22 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2012 Marc-Andre Moreau +# +# 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. + +define_channel("disp") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/disp/ChannelOptions.cmake b/channels/disp/ChannelOptions.cmake new file mode 100644 index 000000000..0e254adad --- /dev/null +++ b/channels/disp/ChannelOptions.cmake @@ -0,0 +1,12 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT OFF) + +define_channel_options(NAME "disp" TYPE "dynamic" + DESCRIPTION "Display Update Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPEDISP]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) diff --git a/channels/disp/client/CMakeLists.txt b/channels/disp/client/CMakeLists.txt new file mode 100644 index 000000000..403a15ce4 --- /dev/null +++ b/channels/disp/client/CMakeLists.txt @@ -0,0 +1,47 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2013 Marc-Andre Moreau +# +# 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. + +define_channel_client("disp") + +set(${MODULE_PREFIX}_SRCS + disp_main.c + disp_main.h) + +include_directories(..) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") + +set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE freerdp + MODULES freerdp-common freerdp-utils) + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-sysinfo) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +if(NOT STATIC_CHANNELS) + install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_PLUGIN_PATH}) +endif() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") + diff --git a/channels/disp/client/disp_main.c b/channels/disp/client/disp_main.c new file mode 100644 index 000000000..feb971550 --- /dev/null +++ b/channels/disp/client/disp_main.c @@ -0,0 +1,341 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Display Update Virtual Channel Extension + * + * Copyright 2013 Marc-Andre Moreau + * + * 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "disp_main.h" + +struct _DISP_CHANNEL_CALLBACK +{ + IWTSVirtualChannelCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + IWTSVirtualChannel* channel; +}; +typedef struct _DISP_CHANNEL_CALLBACK DISP_CHANNEL_CALLBACK; + +struct _DISP_LISTENER_CALLBACK +{ + IWTSListenerCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + DISP_CHANNEL_CALLBACK* channel_callback; +}; +typedef struct _DISP_LISTENER_CALLBACK DISP_LISTENER_CALLBACK; + +struct _DISP_PLUGIN +{ + IWTSPlugin iface; + + IWTSListener* listener; + DISP_LISTENER_CALLBACK* listener_callback; + + UINT32 MaxNumMonitors; + UINT32 MaxMonitorWidth; + UINT32 MaxMonitorHeight; +}; +typedef struct _DISP_PLUGIN DISP_PLUGIN; + +int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback, UINT32 NumMonitors, DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors) +{ + int index; + int status; + wStream* s; + UINT32 type; + UINT32 length; + DISP_PLUGIN* disp; + UINT32 MonitorLayoutSize; + + disp = (DISP_PLUGIN*) callback->plugin; + +#ifdef DISP_PREVIEW + MonitorLayoutSize = 32; +#else + MonitorLayoutSize = 40; +#endif + + length = 8 + 8 + (NumMonitors * MonitorLayoutSize); + + type = DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT; + + s = Stream_New(NULL, length); + + Stream_Write_UINT32(s, type); /* Type (4 bytes) */ + Stream_Write_UINT32(s, length); /* Length (4 bytes) */ + + if (NumMonitors > disp->MaxNumMonitors) + NumMonitors = disp->MaxNumMonitors; + +#ifdef DISP_PREVIEW + Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */ +#else + Stream_Write_UINT32(s, MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */ +#endif + + Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */ + + //fprintf(stderr, "NumMonitors: %d\n", NumMonitors); + + for (index = 0; index < NumMonitors; index++) + { + Monitors[index].Width -= (Monitors[index].Width % 2); + + if (Monitors[index].Width < 200) + Monitors[index].Width = 200; + + if (Monitors[index].Width > disp->MaxMonitorWidth) + Monitors[index].Width = disp->MaxMonitorWidth; + + if (Monitors[index].Height < 200) + Monitors[index].Height = 200; + + if (Monitors[index].Height > disp->MaxMonitorHeight) + Monitors[index].Height = disp->MaxMonitorHeight; + + Stream_Write_UINT32(s, Monitors[index].Flags); /* Flags (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Left); /* Left (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Top); /* Top (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Width); /* Width (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Height); /* Height (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].PhysicalWidth); /* PhysicalWidth (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].PhysicalHeight); /* PhysicalHeight (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].Orientation); /* Orientation (4 bytes) */ + +#if 0 + fprintf(stderr, "\t: Flags: 0x%04X\n", Monitors[index].Flags); + fprintf(stderr, "\t: Left: %d\n", Monitors[index].Left); + fprintf(stderr, "\t: Top: %d\n", Monitors[index].Top); + fprintf(stderr, "\t: Width: %d\n", Monitors[index].Width); + fprintf(stderr, "\t: Height: %d\n", Monitors[index].Height); + fprintf(stderr, "\t: PhysicalWidth: %d\n", Monitors[index].PhysicalWidth); + fprintf(stderr, "\t: PhysicalHeight: %d\n", Monitors[index].PhysicalHeight); + fprintf(stderr, "\t: Orientation: %d\n", Monitors[index].Orientation); +#endif + +#ifndef DISP_PREVIEW + Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */ + Stream_Write_UINT32(s, Monitors[index].DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */ +#endif + } + + Stream_SealLength(s); + + status = callback->channel->Write(callback->channel, Stream_Length(s), Stream_Buffer(s), NULL); + + Stream_Free(s, TRUE); + + return status; +} + +int disp_recv_display_control_caps_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s) +{ + DISP_PLUGIN* disp; + + disp = (DISP_PLUGIN*) callback->plugin; + + Stream_Read_UINT32(s, disp->MaxNumMonitors); /* MaxNumMonitors (4 bytes) */ + Stream_Read_UINT32(s, disp->MaxMonitorWidth); /* MaxMonitorWidth (4 bytes) */ + Stream_Read_UINT32(s, disp->MaxMonitorHeight); /* MaxMonitorHeight (4 bytes) */ + + //fprintf(stderr, "DisplayControlCapsPdu: MaxNumMonitors: %d MaxMonitorWidth: %d MaxMonitorHeight: %d\n", + // disp->MaxNumMonitors, disp->MaxMonitorWidth, disp->MaxMonitorHeight); + + return 0; +} + +int disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s) +{ + UINT32 type; + UINT32 length; + + Stream_Read_UINT32(s, type); /* Type (4 bytes) */ + Stream_Read_UINT32(s, length); /* Length (4 bytes) */ + + //fprintf(stderr, "Type: %d Length: %d\n", type, length); + + switch (type) + { + case DISPLAY_CONTROL_PDU_TYPE_CAPS: + disp_recv_display_control_caps_pdu(callback, s); + break; + + default: + break; + } + + return 0; +} + +static int disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer) +{ + wStream* s; + int status = 0; + DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*) pChannelCallback; + + s = Stream_New(pBuffer, cbSize); + + status = disp_recv_pdu(callback, s); + + Stream_Free(s, FALSE); + + return status; +} + +static int disp_on_close(IWTSVirtualChannelCallback* pChannelCallback) +{ + DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*) pChannelCallback; + + if (callback) + { + free(callback); + } + + return 0; +} + +static int disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, BYTE* Data, int* pbAccept, + IWTSVirtualChannelCallback** ppCallback) +{ + DISP_CHANNEL_CALLBACK* callback; + DISP_LISTENER_CALLBACK* listener_callback = (DISP_LISTENER_CALLBACK*) pListenerCallback; + + callback = (DISP_CHANNEL_CALLBACK*) malloc(sizeof(DISP_CHANNEL_CALLBACK)); + ZeroMemory(callback, sizeof(DISP_CHANNEL_CALLBACK)); + + callback->iface.OnDataReceived = disp_on_data_received; + callback->iface.OnClose = disp_on_close; + callback->plugin = listener_callback->plugin; + callback->channel_mgr = listener_callback->channel_mgr; + callback->channel = pChannel; + listener_callback->channel_callback = callback; + + *ppCallback = (IWTSVirtualChannelCallback*) callback; + + return 0; +} + +static int disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) +{ + int status; + DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin; + + disp->listener_callback = (DISP_LISTENER_CALLBACK*) malloc(sizeof(DISP_LISTENER_CALLBACK)); + ZeroMemory(disp->listener_callback, sizeof(DISP_LISTENER_CALLBACK)); + + disp->listener_callback->iface.OnNewChannelConnection = disp_on_new_channel_connection; + disp->listener_callback->plugin = pPlugin; + disp->listener_callback->channel_mgr = pChannelMgr; + + status = pChannelMgr->CreateListener(pChannelMgr, DISP_DVC_CHANNEL_NAME, 0, + (IWTSListenerCallback*) disp->listener_callback, &(disp->listener)); + + disp->listener->pInterface = disp->iface.pInterface; + + return status; +} + +static int disp_plugin_terminated(IWTSPlugin* pPlugin) +{ + DISP_PLUGIN* disp = (DISP_PLUGIN*) pPlugin; + + if (disp) + { + free(disp); + } + + return 0; +} + +/** + * Channel Client Interface + */ + +int disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonitors, DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors) +{ + DISP_PLUGIN* disp = (DISP_PLUGIN*) context->handle; + DISP_CHANNEL_CALLBACK* callback = disp->listener_callback->channel_callback; + + disp_send_display_control_monitor_layout_pdu(callback, NumMonitors, Monitors); + + return 1; +} + +#ifdef STATIC_CHANNELS +#define DVCPluginEntry disp_DVCPluginEntry +#endif + +int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +{ + int error = 0; + DISP_PLUGIN* disp; + DispClientContext* context; + + disp = (DISP_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "disp"); + + if (disp == NULL) + { + disp = (DISP_PLUGIN*) malloc(sizeof(DISP_PLUGIN)); + + if (disp) + { + ZeroMemory(disp, sizeof(DISP_PLUGIN)); + + disp->iface.Initialize = disp_plugin_initialize; + disp->iface.Connected = NULL; + disp->iface.Disconnected = NULL; + disp->iface.Terminated = disp_plugin_terminated; + + context = (DispClientContext*) malloc(sizeof(DispClientContext)); + + context->handle = (void*) disp; + + context->SendMonitorLayout = disp_send_monitor_layout; + + disp->iface.pInterface = (void*) context; + + disp->MaxNumMonitors = 16; + disp->MaxMonitorWidth = 8192; + disp->MaxMonitorHeight = 8192; + + error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp); + } + } + + return error; +} diff --git a/channels/disp/client/disp_main.h b/channels/disp/client/disp_main.h new file mode 100644 index 000000000..db1ce10c5 --- /dev/null +++ b/channels/disp/client/disp_main.h @@ -0,0 +1,40 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Display Update Virtual Channel Extension + * + * Copyright 2013 Marc-Andre Moreau + * + * 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. + */ + +#ifndef FREERDP_CHANNEL_DISP_CLIENT_MAIN_H +#define FREERDP_CHANNEL_DISP_CLIENT_MAIN_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include + +#define DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002 +#define DISPLAY_CONTROL_PDU_TYPE_CAPS 0x00000003 + +#define DISP_PREVIEW 1 + +#endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */ + diff --git a/channels/drdynvc/client/dvcman.c b/channels/drdynvc/client/dvcman.c index ac897a669..954247d02 100644 --- a/channels/drdynvc/client/dvcman.c +++ b/channels/drdynvc/client/dvcman.c @@ -376,16 +376,13 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channel { DEBUG_WARN("channel rejected by plugin"); - channel->status = 1; - ArrayList_Add(dvcman->channels, channel); + free(channel); return 1; } } } - channel->status = 1; - ArrayList_Add(dvcman->channels, channel); - + free(channel); return 1; } diff --git a/channels/parallel/client/parallel_main.c b/channels/parallel/client/parallel_main.c index 6e35c1ee9..16bf4bbb0 100644 --- a/channels/parallel/client/parallel_main.c +++ b/channels/parallel/client/parallel_main.c @@ -286,6 +286,7 @@ static void parallel_free(DEVICE* device) MessageQueue_PostQuit(parallel->queue, 0); WaitForSingleObject(parallel->thread, INFINITE); + Stream_Free(parallel->device.data, TRUE); MessageQueue_Free(parallel->queue); CloseHandle(parallel->thread); diff --git a/channels/printer/client/printer_main.c b/channels/printer/client/printer_main.c index 89e2ffb81..3826b7c3a 100644 --- a/channels/printer/client/printer_main.c +++ b/channels/printer/client/printer_main.c @@ -179,13 +179,16 @@ static void* printer_thread_func(void* arg) { IRP* irp; PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*) arg; + HANDLE obj[] = {printer_dev->event, printer_dev->stopEvent}; while (1) { - WaitForSingleObject(printer_dev->event, INFINITE); + DWORD rc = WaitForMultipleObjects(2, obj, FALSE, INFINITE); - if (WaitForSingleObject(printer_dev->stopEvent, 0) == WAIT_OBJECT_0) + if (rc == WAIT_OBJECT_0 + 1) break; + else if( rc != WAIT_OBJECT_0 ) + continue; ResetEvent(printer_dev->event); diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index 854fd46ab..81099e6d8 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -96,9 +96,10 @@ struct _RDPEI_PLUGIN RDPINPUT_CONTACT_DATA contacts[MAX_CONTACTS]; RDPINPUT_CONTACT_POINT* contactPoints; - HANDLE mutex; HANDLE event; HANDLE thread; + + CRITICAL_SECTION lock; }; typedef struct _RDPEI_PLUGIN RDPEI_PLUGIN; @@ -160,7 +161,7 @@ static void* rdpei_schedule_thread(void* arg) { status = WaitForSingleObject(rdpei->event, 20); - WaitForSingleObject(rdpei->mutex, INFINITE); + EnterCriticalSection(&rdpei->lock); rdpei_add_frame(context); @@ -170,7 +171,7 @@ static void* rdpei_schedule_thread(void* arg) if (status == WAIT_OBJECT_0) ResetEvent(rdpei->event); - ReleaseMutex(rdpei->mutex); + LeaveCriticalSection(&rdpei->lock); } return NULL; @@ -212,14 +213,14 @@ int rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback) Stream_Seek(s, RDPINPUT_HEADER_LENGTH); Stream_Write_UINT32(s, flags); /* flags (4 bytes) */ - Stream_Write_UINT32(s, RDPINPUT_PROTOCOL_V1); /* protocolVersion (4 bytes) */ + Stream_Write_UINT32(s, RDPINPUT_PROTOCOL_V10); /* protocolVersion (4 bytes) */ Stream_Write_UINT16(s, rdpei->maxTouchContacts); /* maxTouchContacts (2 bytes) */ Stream_SealLength(s); if (!rdpei->thread) { - rdpei->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSection(&rdpei->lock); rdpei->event = CreateEvent(NULL, TRUE, FALSE, NULL); rdpei->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) rdpei_schedule_thread, (void*) rdpei, 0, NULL); } @@ -249,6 +250,7 @@ void rdpei_print_contact_flags(UINT32 contactFlags) int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) { int index; + int rectSize = 2; RDPINPUT_CONTACT_DATA* contact; #ifdef WITH_DEBUG_RDPEI @@ -264,12 +266,18 @@ int rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame) */ rdpei_write_8byte_unsigned(s, frame->frameOffset * 1000); /* frameOffset (EIGHT_BYTE_UNSIGNED_INTEGER) */ - Stream_EnsureRemainingCapacity(s, frame->contactCount * 32); + Stream_EnsureRemainingCapacity(s, frame->contactCount * 64); for (index = 0; index < frame->contactCount; index++) { contact = &frame->contacts[index]; + contact->fieldsPresent |= CONTACT_DATA_CONTACTRECT_PRESENT; + contact->contactRectLeft = contact->x - rectSize; + contact->contactRectTop = contact->y - rectSize; + contact->contactRectRight = contact->x + rectSize; + contact->contactRectBottom = contact->y + rectSize; + #ifdef WITH_DEBUG_RDPEI printf("contact[%d].contactId: %d\n", index, contact->contactId); printf("contact[%d].fieldsPresent: %d\n", index, contact->fieldsPresent); @@ -325,7 +333,7 @@ int rdpei_send_touch_event_pdu(RDPEI_CHANNEL_CALLBACK* callback, RDPINPUT_TOUCH_ wStream* s; UINT32 pduLength; - pduLength = 64 + (frame->contactCount * 32); + pduLength = 64 + (frame->contactCount * 64); s = Stream_New(NULL, pduLength); Stream_Seek(s, RDPINPUT_HEADER_LENGTH); @@ -355,11 +363,13 @@ int rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s) Stream_Read_UINT32(s, protocolVersion); /* protocolVersion (4 bytes) */ - if (protocolVersion != RDPINPUT_PROTOCOL_V1) +#if 0 + if (protocolVersion != RDPINPUT_PROTOCOL_V10) { fprintf(stderr, "Unknown [MS-RDPEI] protocolVersion: 0x%08X\n", protocolVersion); return -1; } +#endif return 0; } @@ -533,7 +543,7 @@ int rdpei_add_contact(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contac RDPINPUT_CONTACT_POINT* contactPoint; RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*) context->handle; - WaitForSingleObject(rdpei->mutex, INFINITE); + EnterCriticalSection(&rdpei->lock); contactPoint = (RDPINPUT_CONTACT_POINT*) &rdpei->contactPoints[contact->contactId]; CopyMemory(&(contactPoint->data), contact, sizeof(RDPINPUT_CONTACT_DATA)); @@ -541,7 +551,7 @@ int rdpei_add_contact(RdpeiClientContext* context, RDPINPUT_CONTACT_DATA* contac SetEvent(rdpei->event); - ReleaseMutex(rdpei->mutex); + LeaveCriticalSection(&rdpei->lock); return 1; } diff --git a/channels/rdpei/client/rdpei_main.h b/channels/rdpei/client/rdpei_main.h index c0d0d2d67..cf4dccee0 100644 --- a/channels/rdpei/client/rdpei_main.h +++ b/channels/rdpei/client/rdpei_main.h @@ -35,7 +35,8 @@ /* Protocol Version */ -#define RDPINPUT_PROTOCOL_V1 0x00010000 +#define RDPINPUT_PROTOCOL_V10 0x00010000 +#define RDPINPUT_PROTOCOL_V101 0x00010001 /* Client Ready Flags */ diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c index df4700e9f..d2ff16a48 100644 --- a/channels/serial/client/serial_main.c +++ b/channels/serial/client/serial_main.c @@ -67,7 +67,6 @@ struct _SERIAL_DEVICE wQueue* queue; LIST* pending_irps; - HANDLE in_event; fd_set read_fds; fd_set write_fds; @@ -324,35 +323,31 @@ static void* serial_thread_func(void* arg) IRP* irp; DWORD status; SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg; + HANDLE ev[] = {serial->stopEvent, Queue_Event(serial->queue)}; while (1) { - if (WaitForSingleObject(serial->stopEvent, 0) == WAIT_OBJECT_0) - break; + status = WaitForMultipleObjects(2, ev, FALSE, 1); - if (WaitForSingleObject(Queue_Event(serial->queue), 10) == WAIT_OBJECT_0) + if (WAIT_OBJECT_0 == status) break; serial->nfds = 1; FD_ZERO(&serial->read_fds); FD_ZERO(&serial->write_fds); - serial->tv.tv_sec = 1; + serial->tv.tv_sec = 0; serial->tv.tv_usec = 0; serial->select_timeout = 0; - irp = (IRP*) Queue_Dequeue(serial->queue); - - if (irp) - serial_process_irp(serial, irp); - - status = WaitForSingleObject(serial->in_event, 0); - - if ((status == WAIT_OBJECT_0) || (status == WAIT_TIMEOUT)) + if (status == WAIT_OBJECT_0 + 1) { - if (serial_check_fds(serial)) - ResetEvent(serial->in_event); + if ((irp = (IRP*) Queue_Dequeue(serial->queue))) + serial_process_irp(serial, irp); + continue; } + + serial_check_fds(serial); } return NULL; @@ -371,10 +366,18 @@ static void serial_free(DEVICE* device) DEBUG_SVC("freeing device"); + /* Stop thread */ SetEvent(serial->stopEvent); + WaitForSingleObject(serial->thread, INFINITE); - /* TODO: free lists */ + serial_tty_free(serial->tty); + /* Clean up resources */ + Stream_Free(serial->device.data, TRUE); + Queue_Free(serial->queue); + list_free(serial->pending_irps); + CloseHandle(serial->stopEvent); + CloseHandle(serial->thread); free(serial); } @@ -387,6 +390,11 @@ static void serial_abort_single_io(SERIAL_DEVICE* serial, UINT32 file_id, UINT32 DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps)); tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } switch (abort_io) { @@ -423,7 +431,6 @@ static void serial_abort_single_io(SERIAL_DEVICE* serial, UINT32 file_id, UINT32 Stream_Write_UINT32(irp->output, 0); irp->Complete(irp); - SetEvent(serial->in_event); break; } @@ -438,6 +445,11 @@ static void serial_check_for_events(SERIAL_DEVICE* serial) SERIAL_TTY* tty; tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps)); @@ -460,8 +472,6 @@ static void serial_check_for_events(SERIAL_DEVICE* serial) prev = irp; irp = (IRP*) list_next(serial->pending_irps, irp); list_remove(serial->pending_irps, prev); - - SetEvent(serial->in_event); } } @@ -485,6 +495,11 @@ void serial_get_timeouts(SERIAL_DEVICE* serial, IRP* irp, UINT32* timeout, UINT3 DEBUG_SVC("length read %u", Length); tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } *timeout = (tty->read_total_timeout_multiplier * Length) + tty->read_total_timeout_constant; *interval_timeout = tty->read_interval_timeout; @@ -499,6 +514,11 @@ static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp) SERIAL_TTY* tty; tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } switch (irp->MajorFunction) { @@ -537,7 +557,6 @@ static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp) irp->IoStatus = STATUS_PENDING; list_enqueue(serial->pending_irps, irp); - SetEvent(serial->in_event); } static void __serial_check_fds(SERIAL_DEVICE* serial) @@ -550,6 +569,11 @@ static void __serial_check_fds(SERIAL_DEVICE* serial) ZeroMemory(&serial->tv, sizeof(struct timeval)); tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } /* scan every pending */ irp = list_peek(serial->pending_irps); @@ -599,10 +623,7 @@ static void __serial_check_fds(SERIAL_DEVICE* serial) irp = (IRP*) list_next(serial->pending_irps, irp); if (irp_completed || (prev->IoStatus == STATUS_SUCCESS)) - { list_remove(serial->pending_irps, prev); - SetEvent(serial->in_event); - } } } @@ -615,6 +636,11 @@ static void serial_set_fds(SERIAL_DEVICE* serial) DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps)); tty = serial->tty; + if(!tty) + { + DEBUG_WARN("tty = %p", tty); + return; + } irp = (IRP*) list_peek(serial->pending_irps); while (irp) @@ -692,7 +718,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) name = device->Name; path = device->Path; - if (name[0] && path[0]) + if ((name && name[0]) && (path && path[0])) { serial = (SERIAL_DEVICE*) malloc(sizeof(SERIAL_DEVICE)); ZeroMemory(serial, sizeof(SERIAL_DEVICE)); @@ -711,13 +737,13 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) serial->path = path; serial->queue = Queue_New(TRUE, -1, -1); serial->pending_irps = list_new(); - serial->in_event = CreateEvent(NULL, TRUE, FALSE, NULL); serial->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); - serial->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL); + serial->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL); } return 0; diff --git a/channels/serial/client/serial_tty.c b/channels/serial/client/serial_tty.c index 23445b2ca..95bf375fe 100644 --- a/channels/serial/client/serial_tty.c +++ b/channels/serial/client/serial_tty.c @@ -412,7 +412,11 @@ BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length) status = read(tty->fd, buffer, *Length); if (status < 0) + { + DEBUG_WARN("failed with %zd, errno=[%d] %s\n", + status, errno, strerror(errno)); return FALSE; + } tty->event_txempty = status; *Length = status; @@ -456,6 +460,9 @@ void serial_tty_free(SERIAL_TTY* tty) { DEBUG_SVC("in"); + if(!tty) + return; + if (tty->fd >= 0) { if (tty->pold_termios) diff --git a/channels/server/CMakeLists.txt b/channels/server/CMakeLists.txt index b86cd6df4..aa15ce965 100644 --- a/channels/server/CMakeLists.txt +++ b/channels/server/CMakeLists.txt @@ -40,7 +40,7 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE winpr - MODULES winpr-crt winpr-synch winpr-interlocked) + MODULES winpr-crt winpr-synch winpr-interlocked winpr-error) set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} PARENT_SCOPE) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c index fa4dd0b3d..4efff88ff 100644 --- a/channels/smartcard/client/smartcard_main.c +++ b/channels/smartcard/client/smartcard_main.c @@ -44,8 +44,7 @@ static void smartcard_free(DEVICE* dev) SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) dev; SetEvent(smartcard->stopEvent); - CloseHandle(smartcard->thread); - CloseHandle(smartcard->irpEvent); + WaitForSingleObject(smartcard->thread, INFINITE); while ((irp = (IRP*) InterlockedPopEntrySList(smartcard->pIrpList)) != NULL) irp->Discard(irp); @@ -55,8 +54,14 @@ static void smartcard_free(DEVICE* dev) /* Begin TS Client defect workaround. */ while ((CompletionIdInfo = (COMPLETIONIDINFO*) list_dequeue(smartcard->CompletionIds)) != NULL) - free(CompletionIdInfo); + free(CompletionIdInfo); + CloseHandle(smartcard->thread); + CloseHandle(smartcard->irpEvent); + CloseHandle(smartcard->stopEvent); + CloseHandle(smartcard->CompletionIdsMutex); + + Stream_Free(smartcard->device.data, TRUE); list_free(smartcard->CompletionIds); /* End TS Client defect workaround. */ @@ -119,13 +124,16 @@ static void smartcard_process_irp_thread_func(SMARTCARD_IRP_WORKER* irpWorker) static void* smartcard_thread_func(void* arg) { SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg; + HANDLE ev[] = {smartcard->irpEvent, smartcard->stopEvent}; while (1) { - WaitForSingleObject(smartcard->irpEvent, INFINITE); + DWORD status = WaitForSingleObject(2, ev, FALSE, INFINITE); - if (WaitForSingleObject(smartcard->stopEvent, 0) == WAIT_OBJECT_0) + if (status == WAIT_OBJECT_0 + 1) break; + else if(status != WAIT_OBJECT_0) + continue; ResetEvent(smartcard->irpEvent); smartcard_process_irp_list(smartcard); diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 9e2c1674d..9ead22b81 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -669,7 +669,6 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder * decoder, TS_AM_MEDIA_TYPE * return FALSE; } - return TRUE; } @@ -1133,12 +1132,12 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder * decoder, const BYTE * data, U if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) { - DEBUG_DVC("tsmf_gstreamer_decodeEx_VIDEO. Start:(%llu) End:(%llu) Duration:(%llu) Last End:(%llu)", + DEBUG_DVC("tsmf_gstreamer_decodeEx_VIDEO. Start:(%"PRIu64") End:(%"PRIu64") Duration:(%"PRIu64") Last End:(%"PRIu64")", start_time, end_time, duration, mdecoder->last_sample_end_time); } else { - DEBUG_DVC("tsmf_gstreamer_decodeEX_AUDIO. Start:(%llu) End:(%llu) Duration:(%llu) Last End:(%llu)", + DEBUG_DVC("tsmf_gstreamer_decodeEx_AUDIO. Start:(%"PRIu64") End:(%"PRIu64") Duration:(%"PRIu64") Last End:(%"PRIu64")", start_time, end_time, duration, mdecoder->last_sample_end_time); } @@ -1176,7 +1175,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder * decoder, const BYTE * data, U */ if (start_time > (mdecoder->last_sample_end_time + 10000000) || (end_time + 10000000) < mdecoder->last_sample_end_time) { - DEBUG_DVC("tsmf_gstreamer_decodeEx: start_time=[%llu] > last_sample_end_time=[%llu]", start_time, mdecoder->last_sample_end_time); + DEBUG_DVC("tsmf_gstreamer_decodeEx: start_time=[%"PRIu64"] > last_sample_end_time=[%"PRIu64"]", start_time, mdecoder->last_sample_end_time); DEBUG_DVC("tsmf_gstreamer_decodeEx: Stream seek detected - flushing element."); tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL); gst_object_unref(mdecoder->pipe); @@ -1205,7 +1204,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder * decoder, const BYTE * data, U if (fout) { - fprintf(fout, "%"PRIu64"\n", (long unsigned int) start_time); + fprintf(fout, "%"PRIu64"\n", start_time); fclose(fout); } @@ -1231,7 +1230,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder * decoder, const BYTE * data, U if (fin) { UINT64 AStartTime = 0; - fscanf(fin, "%"PRIu64, (long unsigned int*) &AStartTime); + fscanf(fin, "%"PRIu64, &AStartTime); fclose(fin); if (start_time > AStartTime) { @@ -1265,7 +1264,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder * decoder, const BYTE * data, U if (fin) { UINT64 VStartTime = 0; - fscanf(fin, "%"PRIu64, (long unsigned int*) &VStartTime); + fscanf(fin, "%"PRIu64, &VStartTime); fclose(fin); if (start_time > VStartTime) { @@ -1283,7 +1282,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder * decoder, const BYTE * data, U pthread_mutex_unlock(&mdecoder->gst_mutex); DEBUG_WARN("tsmf_gstreamer_decodeEx: gst_buffer_try_new_and_alloc(%d) failed.", data_size); return FALSE; - } + } gst_buffer_set_caps(gst_buf, mdecoder->gst_caps); memcpy(GST_BUFFER_MALLOCDATA(gst_buf), data, data_size); GST_BUFFER_TIMESTAMP(gst_buf) = tsmf_gstreamer_timestamp_ms_to_gst(start_time); @@ -1325,20 +1324,21 @@ static void tsmf_gstreamer_change_volume(ITSMFDecoder * decoder, UINT32 newVolum if (mdecoder->shutdown) return; - if (!mdecoder->aVolume) + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) return; - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + mdecoder->gstMuted = (BOOL) muted; + DEBUG_DVC("tsmf_gstreamer_change_volume: mute=[%d]", mdecoder->gstMuted); + mdecoder->gstVolume = (double) newVolume / (double) 10000; + DEBUG_DVC("tsmf_gstreamer_change_volume: gst_new_vol=[%f]", mdecoder->gstVolume); + + if (!mdecoder->aVolume) return; if (!G_IS_OBJECT(mdecoder->aVolume)) return; - mdecoder->gstMuted = (BOOL) muted; - DEBUG_DVC("tsmf_gstreamer_change_volume: mute=[%d]", mdecoder->gstMuted); g_object_set(mdecoder->aVolume, "mute", mdecoder->gstMuted, NULL); - mdecoder->gstVolume = (double) newVolume / (double) 10000; - DEBUG_DVC("tsmf_gstreamer_change_volume: gst_new_vol=[%f]", mdecoder->gstVolume); g_object_set(mdecoder->aVolume, "volume", mdecoder->gstVolume, NULL); } @@ -1482,7 +1482,7 @@ static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder * decoder) GstFormat fmt = GST_FORMAT_TIME; gint64 pos = 0; gst_element_query_position (mdecoder->outsink, &fmt, &pos); - DEBUG_DVC("tsmf_gstreamer_current_pos=[%llu]", pos); + DEBUG_DVC("tsmf_gstreamer_current_pos=[%"PRIu64"]", pos); return pos/100; } @@ -1524,13 +1524,14 @@ static void tsmf_gstreamer_update_rendering_area(ITSMFDecoder * decoder, int new { if (info->noutput > 0) { - if (info->outputs[0] == primary_output) + if (info->outputs[0] == primary_output || i == 0) { mdecoder->xOffset = info->x; mdecoder->yOffset = info->y; } DEBUG_DVC("output %d ID: %lu (x,y): (%d,%d) (w,h): (%d,%d) primary: %d", i, info->outputs[0], info->x, info->y, info->width, info->height, (info->outputs[0] == primary_output)); } + XRRFreeCrtcInfo(info); } } } @@ -1545,7 +1546,12 @@ static void tsmf_gstreamer_update_rendering_area(ITSMFDecoder * decoder, int new if(mdecoder->subwin) { XMoveWindow(mdecoder->disp, mdecoder->subwin, anewX, anewY); - XResizeWindow(mdecoder->disp, mdecoder->subwin, newWidth, newHeight); + if(newWidth > 0 && newHeight > 0) { + XResizeWindow(mdecoder->disp, mdecoder->subwin, newWidth, newHeight); + } else { + XResizeWindow(mdecoder->disp, mdecoder->subwin, 1, 1); + } + XSync(mdecoder->disp, FALSE); XShapeCombineRectangles (mdecoder->disp, mdecoder->subwin, ShapeBounding, 0, 0,(XRectangle*) rectangles, numRectangles, ShapeSet, Unsorted); XSync(mdecoder->disp, FALSE); @@ -1599,7 +1605,7 @@ ITSMFDecoder* freerdp_tsmf_client_decoder_subsystem_entry(void) decoder->xOffset = 0; decoder->yOffset = 0; decoder->offsetObtained = FALSE; - decoder->gstVolume = 1.0; + decoder->gstVolume = 0.5; decoder->gstMuted = FALSE; decoder->state = GST_STATE_VOID_PENDING; /* No real state yet */ pthread_mutex_init(&decoder->gst_mutex, NULL); diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index 59059dbba..03229adb5 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -127,8 +127,6 @@ int tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman) return 0; } -static TSMF_PRESENTATION* pexisted = 0; - int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman) { int status = 0; @@ -136,15 +134,16 @@ int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman) DEBUG_DVC(""); - if (pexisted) + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); + if (presentation) { + DEBUG_DVC("Presentation already exists"); ifman->output_pending = FALSE; return 0; } presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback); - pexisted = presentation; if (presentation == NULL) status = 1; @@ -283,8 +282,8 @@ int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman) if (presentation) tsmf_presentation_free(presentation); - - pexisted = 0; + else + DEBUG_WARN("unknown presentation id"); Stream_EnsureRemainingCapacity(ifman->output, 4); Stream_Write_UINT32(ifman->output, 0); /* Result */ diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index d1449237e..f31175150 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -84,6 +84,9 @@ struct _TSMF_PRESENTATION UINT64 audio_start_time; UINT64 audio_end_time; + UINT32 volume; + UINT32 muted; + HANDLE mutex; HANDLE thread; @@ -282,6 +285,9 @@ TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, IWTSVirtualChannelCal memcpy(presentation->presentation_id, guid, GUID_SIZE); presentation->channel_callback = pChannelCallback; + presentation->volume = 5000; /* 50% */ + presentation->muted = 0; + presentation->mutex = CreateMutex(NULL, FALSE, NULL); presentation->stream_list = list_new(); @@ -786,6 +792,9 @@ void tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 ne LIST_ITEM* item; TSMF_STREAM* stream; + presentation->volume = newVolume; + presentation->muted = muted; + for (item = presentation->stream_list->head; item; item = item->next) { stream = (TSMF_STREAM*) item->data; @@ -964,7 +973,10 @@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id) stream->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tsmf_stream_playback_func, stream, CREATE_SUSPENDED, NULL); stream->sample_list = Queue_New(TRUE, -1, -1); + stream->sample_list->object.fnObjectFree = free; + stream->sample_ack_list = Queue_New(TRUE, -1, -1); + stream->sample_ack_list->object.fnObjectFree = free; WaitForSingleObject(presentation->mutex, INFINITE); list_enqueue(presentation->stream_list, stream); @@ -1026,6 +1038,7 @@ void tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s) stream->width = mediatype.Width; stream->height = mediatype.Height; stream->decoder = tsmf_load_decoder(name, &mediatype); + tsmf_stream_change_volume(stream, stream->presentation->volume, stream->presentation->muted); } void tsmf_stream_end(TSMF_STREAM* stream) diff --git a/channels/urbdrc/client/CMakeLists.txt b/channels/urbdrc/client/CMakeLists.txt index 53391f100..736097122 100644 --- a/channels/urbdrc/client/CMakeLists.txt +++ b/channels/urbdrc/client/CMakeLists.txt @@ -31,6 +31,10 @@ set(${MODULE_PREFIX}_SRCS include_directories(..) +find_package(UDev REQUIRED) +find_package(UUID REQUIRED) +find_package(DbusGlib REQUIRED) + add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") @@ -38,9 +42,9 @@ set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") #set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} libusb-devman) set(${MODULE_PREFIX}_LIBS - dbus-glib-1 - udev - uuid) + ${DBUS_GLIB_LIBRARIES} + ${UDEV_LIBRARIES} + ${UUID_LIBRARIES}) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} diff --git a/channels/urbdrc/client/libusb/CMakeLists.txt b/channels/urbdrc/client/libusb/CMakeLists.txt index 0f66539da..47688b9b0 100644 --- a/channels/urbdrc/client/libusb/CMakeLists.txt +++ b/channels/urbdrc/client/libusb/CMakeLists.txt @@ -27,6 +27,8 @@ set(${MODULE_PREFIX}_SRCS include_directories(..) +find_package(libusb-1.0 REQUIRED) + add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "") @@ -35,9 +37,10 @@ set(${MODULE_PREFIX}_LIBS ${CMAKE_THREAD_LIBS_INIT}) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} - dbus-glib-1 - usb-1.0 - udev) + ${DBUS_GLIB_LIBRARIES} + ${UUID_LIBRARIES} + ${LIBUSB_1_LIBRARIES} + ) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} diff --git a/client/Android/FreeRDPCore/jni/android_freerdp.c b/client/Android/FreeRDPCore/jni/android_freerdp.c index 632ca82c2..f0046dcc5 100644 --- a/client/Android/FreeRDPCore/jni/android_freerdp.c +++ b/client/Android/FreeRDPCore/jni/android_freerdp.c @@ -686,7 +686,8 @@ JNIEXPORT void JNICALL jni_freerdp_set_gateway_info(JNIEnv *env, jclass cls, jin settings->GatewayUsername = strdup(gatewayusername); settings->GatewayPassword = strdup(gatewaypassword); settings->GatewayDomain = strdup(gatewaydomain); - settings->GatewayUsageMethod = TRUE; + settings->GatewayUsageMethod = TSC_PROXY_MODE_DIRECT; + settings->GatewayEnabled = TRUE; settings->GatewayUseSameCredentials = FALSE; (*env)->ReleaseStringUTFChars(env, jgatewayhostname, gatewayhostname); diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionActivity.java b/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionActivity.java index 055b48b73..defaf9247 100644 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionActivity.java +++ b/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionActivity.java @@ -248,6 +248,9 @@ public class SessionActivity extends Activity { Log.v(TAG, "OnConnectionFailure"); + // remove pending move events + uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); + if(progressDialog != null) { progressDialog.dismiss(); @@ -264,7 +267,10 @@ public class SessionActivity extends Activity private void OnDisconnected(Context context) { Log.v(TAG, "OnDisconnected"); - + + // remove pending move events + uiHandler.removeMessages(UIHandler.SEND_MOVE_EVENT); + if(progressDialog != null) { progressDialog.dismiss(); @@ -434,6 +440,7 @@ public class SessionActivity extends Activity keyboardMapper = new KeyboardMapper(); keyboardMapper.init(this); + keyboardMapper.reset(this); modifiersKeyboard = new Keyboard(getApplicationContext(), R.xml.modifiers_keyboard); specialkeysKeyboard = new Keyboard(getApplicationContext(), R.xml.specialkeys_keyboard); diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java b/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java index 83f6ca562..06b800a80 100644 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java +++ b/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java @@ -65,7 +65,9 @@ public abstract class ClipboardManagerProxy { String data = null; if (clip != null && clip.getItemCount() > 0) { - data = clip.getItemAt(0).getText().toString(); + CharSequence cs = clip.getItemAt(0).getText(); + if (cs != null) + data = cs.toString(); } if (mListener != null) { mListener.onClipboardChanged(data); diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 2543bb028..e78c37517 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -57,4 +57,4 @@ endif() if (WITH_DOTNET) add_subdirectory(DotNetClient) -endif() \ No newline at end of file +endif() diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt index 78dfca32b..2344f46a1 100755 --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -1,10 +1,10 @@ + project(MacFreeRDP-library) set(MODULE_NAME "MacFreeRDP-library") set(MODULE_OUTPUT_NAME "MacFreeRDP") -set(MODULE_PREFIX "FREERDP_CLIENT_MAC-LIB") +set(MODULE_PREFIX "FREERDP_CLIENT_MAC_LIBRARY") -# Import frameworks find_library(FOUNDATION_LIBRARY Foundation) find_library(COCOA_LIBRARY Cocoa) find_library(APPKIT_LIBRARY AppKit) @@ -21,53 +21,57 @@ set(MACOSX_BUNDLE_SHORT_VERSION_STRING 1.1.0) set(MACOSX_BUNDLE_BUNDLE_VERSION 1.1.0) set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2013. All Rights Reserved.") -set(${MODULE_NAME}_RESOURCES "en.lproj/InfoPlist.strings") +set(${MODULE_PREFIX}_XIBS PasswordDialog.xib) -# OS X Interface Builder files -file(GLOB ${MODULE_NAME}_XIBS *.xib) +set(${MODULE_PREFIX}_SOURCES "") -# source files -file(GLOB ${MODULE_NAME}_SRC *.c *.m) +set(${MODULE_PREFIX}_OBJECTIVE_SOURCES + main.m + mf_client.m + MRDPCursor.m + MRDPView.m + PasswordDialog.m) -# header files -file(GLOB ${MODULE_NAME}_HEADERS *.h) +list(APPEND ${MODULE_PREFIX}_SOURCES ${${MODULE_PREFIX}_OBJECTIVE_SOURCES}) + +set(${MODULE_PREFIX}_HEADERS + mfreerdp.h + mf_client.h + MRDPCursor.h + MRDPView.h + PasswordDialog.h) + +set(${MODULE_PREFIX}_RESOURCES "en.lproj/InfoPlist.strings") # Include XIB file in Xcode resources. if("${CMAKE_GENERATOR}" MATCHES "Xcode") message(STATUS "Adding Xcode XIB resources for ${MODULE_NAME}") - set(${MODULE_NAME}_RESOURCES ${${MODULE_NAME}_RESOURCES} ${${MODULE_NAME}_XIBS}) + set(${MODULE_PREFIX}_RESOURCES ${${MODULE_PREFIX}_RESOURCES} ${${MODULE_PREFIX}_XIBS}) endif() add_library(${MODULE_NAME} SHARED ../common/client.c - ${${MODULE_NAME}_SRC} - ${${MODULE_NAME}_HEADERS} - ${${MODULE_NAME}_RESOURCES}) + ${${MODULE_PREFIX}_SOURCES} + ${${MODULE_PREFIX}_HEADERS} + ${${MODULE_PREFIX}_RESOURCES}) set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "${MODULE_OUTPUT_NAME}") # configures the framework to always be looked for in the application bundle in the Frameworks sub-folder. -SET_TARGET_PROPERTIES(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_INSTALL_PATH @executable_path/../Frameworks/) +set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_INSTALL_PATH @executable_path/../Frameworks/) set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${EXECUTABLE_OUTPUT_PATH} RUNTIME_OUTPUT_DIRECTORY_RELEASE ${EXECUTABLE_OUTPUT_PATH}) -# Support for automatic reference counting requires non-fragile abi. -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-nonfragile-abi") - -set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_ARCHS "$(NATIVE_ARCH_ACTUAL)") - -set(MODULE_VERSION, 1.1.0) - set_target_properties(${MODULE_NAME} PROPERTIES FRAMEWORK TRUE MACOSX_FRAMEWORK_IDENTIFIER com.awakecoding.${MODULE_NAME} FRAMEWORK_VERSION 1.1.0 MACOSX_FRAMEWORK_SHORT_VERSION_STRING 1.1.0 - MACOSX_FRAMEWORK_BUNDLE_VERSION 1.1.0 - INSTALL_NAME_DIR "@executable_path/../../Frameworks" + MACOSX_FRAMEWORK_BUNDLE_BUNDLE_VERSION 1.1.0 + INSTALL_NAME_DIR "@executable_path/../Frameworks" MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist BUILD_WITH_INSTALL_RPATH 1) @@ -106,15 +110,15 @@ if (${BUILD_SHARED_LIBS}) add_custom_command(TARGET ${MODULE_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "$" - "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_NAME}.framework/Contents/$" + "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Contents/$" COMMENT "Copying ${LIB} to output directory" COMMAND install_name_tool -change "$" - "@executable_path/../Frameworks/${MODULE_NAME}.framework/Contents/$" - "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_NAME}.framework/${MODULE_NAME}" + "@executable_path/../Frameworks/${MODULE_OUTPUT_NAME}.framework/Contents/$" + "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/${MODULE_NAME}" COMMENT Setting install name for ${LIB} COMMAND "${CMAKE_COMMAND}" -E echo install_name_tool -change "$" - "@executable_path/../Frameworks/${MODULE_NAME}.framework/Contents/$" - "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_NAME}.framework/${MODULE_NAME}") + "@executable_path/../Frameworks/${MODULE_OUTPUT_NAME}.framework/Contents/$" + "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/${MODULE_NAME}") endforeach() # Call install_name_tool to reassign the library install names in dependent libraries @@ -123,8 +127,8 @@ if (${BUILD_SHARED_LIBS}) # message("adding post-build dependency: ${LIB}") add_custom_command(TARGET ${MODULE_NAME} POST_BUILD COMMAND install_name_tool -change "$" - "@executable_path/../Frameworks/${MODULE_NAME}.framework/Contents/$" - "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_NAME}.framework/Contents/$" + "@executable_path/../Frameworks/${MODULE_OUTPUT_NAME}.framework/Contents/$" + "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Contents/$" COMMENT Setting install name for ${LIB} in module ${DEST}) endforeach() endforeach() @@ -132,7 +136,7 @@ if (${BUILD_SHARED_LIBS}) endif() # Add post-build NIB file generation in unix makefiles. XCode handles this implicitly. -if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") +# if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") message(STATUS "Adding post-build NIB file generation event for ${MODULE_NAME}") # Make sure we can find the 'ibtool' program. If we can NOT find it we @@ -145,7 +149,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") # Make sure the 'Resources' Directory is correctly created before we build add_custom_command(TARGET ${MODULE_NAME} PRE_BUILD - COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_NAME}.app/Contents/Resources) + COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Versions/${MACOSX_BUNDLE_SHORT_VERSION_STRING}/Resources) # Compile the .xib files using the 'ibtool' program with the destination being the app package foreach(xib ${${MODULE_NAME}_XIBS}) @@ -153,22 +157,23 @@ if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") add_custom_command (TARGET ${MODULE_NAME} POST_BUILD COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text - --compile ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_NAME}.app/Contents/Resources/${XIB_WE}.nib ${xib} + --compile ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Versions/${MACOSX_BUNDLE_SHORT_VERSION_STRING}/Resources/${XIB_WE}.nib ${CMAKE_CURRENT_SOURCE_DIR}/${xib} COMMENT "Compiling ${xib}") endforeach() -endif() +# endif() # Copy the public header files into the framework -foreach(HEADER ${${MODULE_NAME}_HEADERS}) +foreach(HEADER ${${MODULE_PREFIX}_HEADERS}) # message("adding post-build dependency: ${LIB}") add_custom_command(TARGET ${MODULE_NAME} POST_BUILD - COMMAND ditto ${HEADER} ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_NAME}.framework/Headers/ + COMMAND ditto ${CMAKE_CURRENT_SOURCE_DIR}/${HEADER} ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/ COMMENT Copying public header files to ${MODULE_NAME}) endforeach() # Copy the FreeRDP header files into the framework add_custom_command(TARGET ${MODULE_NAME} POST_BUILD - COMMAND ditto ${CMAKE_SOURCE_DIR}/include/freerdp ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_NAME}.framework/Headers/freerdp + COMMAND ditto ${CMAKE_SOURCE_DIR}/include/freerdp ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/freerdp + COMMAND ditto ${CMAKE_SOURCE_DIR}/winpr/include/winpr ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/winpr COMMENT Copying FreeRDP header files to ${MODULE_NAME}) add_subdirectory(cli) diff --git a/client/Mac/MRDPView.h b/client/Mac/MRDPView.h index 2cc67c2d4..289dae5ce 100755 --- a/client/Mac/MRDPView.h +++ b/client/Mac/MRDPView.h @@ -41,14 +41,11 @@ @interface MRDPView : NSView { - CFRunLoopSourceRef run_loop_src_channels; - CFRunLoopSourceRef run_loop_src_update; - CFRunLoopSourceRef run_loop_src_input; - NSBitmapImageRep* bmiRep; NSMutableArray* cursors; NSMutableArray* windows; NSTimer* pasteboard_timer; + NSCursor* currentCursor; NSRect prevWinPosition; int titleBarHeight; freerdp* instance; @@ -61,7 +58,6 @@ char** argv; NSPoint savedDragLocation; - BOOL mouseInClientArea; BOOL firstCreateWindow; BOOL isMoveSizeInProgress; BOOL skipResizeOnce; @@ -78,6 +74,10 @@ int kdlmeta; int kdrmeta; int kdcapslock; + + BOOL initialized; + + NSImageView* imageView; @public NSPasteboard* pasteboard_rd; /* for reading from clipboard */ @@ -88,11 +88,11 @@ } - (int) rdpStart :(rdpContext*) rdp_context; -- (void) rdpConnectError; -- (void) rdpRemoteAppError; +- (void) setCursor: (NSCursor*) cursor; + - (void) onPasteboardTimerFired :(NSTimer *) timer; - (void) releaseResources; -- (void) setViewSize : (int) width : (int) height; +- (void) setViewSize : (int) w : (int) h; @property (assign) int is_connected; @@ -107,3 +107,9 @@ #define PTR_FLAGS_BUTTON2 0x2000 #define PTR_FLAGS_BUTTON3 0x4000 #define WheelRotationMask 0x01FF + +BOOL mac_pre_connect(freerdp* instance); +BOOL mac_post_connect(freerdp* instance); +BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain); +int mac_receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size); +DWORD mac_client_thread(void* param); diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index fe516b543..d12f2da3a 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -42,6 +42,8 @@ * - */ +#include + #include "mf_client.h" #import "mfreerdp.h" #import "MRDPView.h" @@ -63,7 +65,6 @@ #import "freerdp/client/file.h" #import "freerdp/client/cmdline.h" - /****************************************** Forward declarations ******************************************/ @@ -75,19 +76,14 @@ void mf_Pointer_Set(rdpContext* context, rdpPointer* pointer); void mf_Pointer_SetNull(rdpContext* context); void mf_Pointer_SetDefault(rdpContext* context); // int rdp_connect(void); -BOOL mac_pre_connect(freerdp* instance); -BOOL mac_post_connect(freerdp* instance); -BOOL mac_authenticate(freerdp* instance, char** username, char** password, char** domain); void mac_set_bounds(rdpContext* context, rdpBounds* bounds); void mac_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap); void mac_begin_paint(rdpContext* context); void mac_end_paint(rdpContext* context); void mac_save_state_info(freerdp* instance, rdpContext* context); -static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); -static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); -static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info); -int register_update_fds(freerdp* instance); -int register_input_fds(freerdp* instance); +static void update_activity_cb(freerdp* instance); +static void input_activity_cb(freerdp* instance); +static void channel_activity_cb(freerdp* instance); int invoke_draw_rect(rdpContext* context); int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data); int receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size); @@ -101,6 +97,9 @@ void cliprdr_process_text(freerdp* instance, BYTE* data, int len); void cliprdr_send_supported_format_list(freerdp* instance); int register_channel_fds(int* fds, int count, freerdp* instance); + +DWORD mac_client_thread(void* param); + struct cursor { rdpPointer* pointer; @@ -124,57 +123,112 @@ struct rgba_data - (int) rdpStart:(rdpContext*) rdp_context { - int status; mfContext* mfc; rdpSettings* settings; EmbedWindowEventArgs e; + [self initializeView]; + context = rdp_context; mfc = (mfContext*) rdp_context; instance = context->instance; settings = context->settings; - mfc->view = self; EventArgsInit(&e, "mfreerdp"); e.embed = TRUE; e.handle = (void*) self; PubSub_OnEmbedWindow(context->pubSub, context, &e); + [self setViewSize :instance->settings->DesktopWidth :instance->settings->DesktopHeight]; - context->instance->PreConnect = mac_pre_connect; - context->instance->PostConnect = mac_post_connect; - context->instance->ReceiveChannelData = mac_receive_channel_data; - context->instance->Authenticate = mac_authenticate; - - // TODO - // instance->Authenticate = mf_authenticate; - // instance->VerifyCertificate = mf_verify_certificate; - // instance->LogonErrorInfo = mf_logon_error_info; - - status = freerdp_connect(context->instance); + mfc->thread = CreateThread(NULL, 0, mac_client_thread, (void*) context, 0, &mfc->mainThreadId); - if (!status) - { - [self setIs_connected:0]; - [self rdpConnectError]; - return 1; - } - - /* register update message queue with the RunLoop */ - register_update_fds(context->instance); - - /* register update message queue with the RunLoop */ - register_input_fds(context->instance); - - /* register channel events with the RunLoop */ - register_channels_fds(context->instance); - - freerdp_check_fds(context->instance); - - [self setIs_connected:1]; - return 0; } +DWORD mac_client_thread(void* param) +{ + @autoreleasepool + { + int status; + HANDLE events[4]; + HANDLE input_event; + HANDLE update_event; + HANDLE channels_event; + + DWORD nCount; + rdpContext* context = (rdpContext*) param; + mfContext* mfc = (mfContext*) context; + freerdp* instance = context->instance; + MRDPView* view = mfc->view; + + status = freerdp_connect(context->instance); + + if (!status) + { + [view setIs_connected:0]; + return 0; + } + + [view setIs_connected:1]; + + nCount = 0; + + events[nCount++] = mfc->stopEvent; + + if (instance->settings->AsyncUpdate) + { + events[nCount++] = update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE); + } + + if (instance->settings->AsyncInput) + { + events[nCount++] = input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); + } + + if (instance->settings->AsyncChannels) + { + events[nCount++] = channels_event = freerdp_channels_get_event_handle(instance); + } + + while (1) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (WaitForSingleObject(mfc->stopEvent, 0) == WAIT_OBJECT_0) + { + break; + } + + if (instance->settings->AsyncUpdate) + { + if (WaitForSingleObject(update_event, 0) == WAIT_OBJECT_0) + { + update_activity_cb(instance); + } + } + + if (instance->settings->AsyncInput) + { + if (WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0) + { + input_activity_cb(instance); + } + } + + if (instance->settings->AsyncChannels) + { + if (WaitForSingleObject(channels_event, 0) == WAIT_OBJECT_0) + { + channel_activity_cb(instance); + } + } + } + + ExitThread(0); + return 0; + } +} + /************************************************************************ methods we override ************************************************************************/ @@ -185,7 +239,7 @@ struct rgba_data - (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; + self = [super initWithFrame:frame]; if (self) { @@ -201,24 +255,50 @@ struct rgba_data //TODO - Expose this code as a public method, because awakeFromNib // won't be called if the view is created dynamically -- (void) awakeFromNib +- (void) viewDidLoad { - // store our window dimensions - width = [self frame].size.width; - height = [self frame].size.height; - titleBarHeight = 22; - - [[self window] becomeFirstResponder]; - [[self window] setAcceptsMouseMovedEvents:YES]; - - cursors = [[NSMutableArray alloc] initWithCapacity:10]; + [self initializeView]; +} - // setup a mouse tracking area - NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil]; - - [self addTrackingArea:trackingArea]; - - mouseInClientArea = YES; +- (void) initializeView +{ + if (!initialized) + { + // store our window dimensions + width = [self frame].size.width; + height = [self frame].size.height; + titleBarHeight = 22; + + [[self window] becomeFirstResponder]; + [[self window] setAcceptsMouseMovedEvents:YES]; + + cursors = [[NSMutableArray alloc] initWithCapacity:10]; + + // setup a mouse tracking area + NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil]; + + [self addTrackingArea:trackingArea]; + + // Set the default cursor + currentCursor = [NSCursor arrowCursor]; + + initialized = YES; + } +} + +- (void) setCursor: (NSCursor*) cursor +{ + self->currentCursor = cursor; + [[self window] invalidateCursorRectsForView:self]; + + [imageView setImage:[currentCursor image]]; +} + + +// Set the current cursor +- (void) resetCursorRects +{ + [self addCursorRect:[self visibleRect] cursor:currentCursor]; } /** ********************************************************************* @@ -596,7 +676,8 @@ struct rgba_data - (void) releaseResources { int i; - + + for (i = 0; i < argc; i++) { if (argv[i]) @@ -610,20 +691,6 @@ struct rgba_data if (pixel_data) free(pixel_data); - - if (run_loop_src_update != 0) - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_update, kCFRunLoopDefaultMode); - - if (run_loop_src_input != 0) - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_input, kCFRunLoopDefaultMode); - - if (run_loop_src_channels != 0) - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), run_loop_src_channels, kCFRunLoopDefaultMode); - - freerdp_client_stop(self->context); - - freerdp_client_context_free(self->context); - } /** ********************************************************************* @@ -657,94 +724,6 @@ struct rgba_data instance methods ************************************************************************/ -/** ********************************************************************* - * double check that a mouse event occurred in our client view - ***********************************************************************/ - -- (BOOL) eventIsInClientArea :(NSEvent *) event :(int *) xptr :(int *) yptr -{ - NSPoint loc = [event locationInWindow]; - int x = (int) loc.x; - int y = (int) loc.y; - - if ((x < 0) || (y < 0)) - { - if (mouseInClientArea) - { - // set default cursor before leaving client area - mouseInClientArea = NO; - NSCursor *cur = [NSCursor arrowCursor]; - [cur set]; - } - - return NO; - } - - if ((x > width) || (y > height)) - { - if (mouseInClientArea) - { - // set default cursor before leaving client area - mouseInClientArea = NO; - NSCursor *cur = [NSCursor arrowCursor]; - [cur set]; - } - - return NO; - } - - // on Mac origin is at lower left, but we want it on upper left - y = height - y; - - *xptr = x; - *yptr = y; - mouseInClientArea = YES; - return YES; -} - -/** ********************************************************************* - * called when we fail to connect to a RDP server - ***********************************************************************/ - -- (void) rdpConnectError -{ - NSString* message = @"Error connecting to server"; - if (connectErrorCode == AUTHENTICATIONERROR) - { - message = [NSString stringWithFormat:@"%@:\n%@", message, @"Authentication failure, check credentials."]; - } - - NSAlert *alert = [[NSAlert alloc] init]; - [alert setMessageText:message]; - [alert beginSheetModalForWindow:[self window] - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; -} - -/** ********************************************************************* - * called when we fail to launch remote app on RDP server - ***********************************************************************/ - -- (void) rdpRemoteAppError -{ - NSAlert *alert = [[NSAlert alloc] init]; - [alert setMessageText:@"Error starting remote app on specified server"]; - [alert beginSheetModalForWindow:[self window] - modalDelegate:self - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; -} - -/** ********************************************************************* - * just a terminate selector for above call - ***********************************************************************/ - -- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci -{ - [NSApp terminate:nil]; -} - - (void) onPasteboardTimerFired :(NSTimer*) timer { int i; @@ -782,8 +761,17 @@ struct rgba_data outerRect.size.height = h + heightDiff; [[self window] setMaxSize:outerRect.size]; [[self window] setMinSize:outerRect.size]; - [[self window] setFrame:outerRect display:YES]; - + + @try + { + [[self window] setFrame:outerRect display:YES]; + } + @catch (NSException * e) { + NSLog(@"Exception: %@", e); + } + @finally { + } + // set client area to specified dimensions innerRect.size.width = w; innerRect.size.height = h; @@ -815,9 +803,6 @@ BOOL mac_pre_connect(freerdp* instance) instance->update->EndPaint = mac_end_paint; instance->update->SetBounds = mac_set_bounds; //instance->update->BitmapUpdate = mac_bitmap_update; - - mfContext *mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; settings = instance->settings; @@ -868,8 +853,6 @@ BOOL mac_pre_connect(freerdp* instance) settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; - [view setViewSize :instance->settings->DesktopWidth :instance->settings->DesktopHeight]; - freerdp_channels_pre_connect(instance->context->channels, instance); return TRUE; @@ -888,13 +871,7 @@ BOOL mac_pre_connect(freerdp* instance) BOOL mac_post_connect(freerdp* instance) { - int index; - int fds[32]; UINT32 flags; - int rd_count = 0; - int wr_count = 0; - void* rd_fds[32]; - void* wr_fds[32]; rdpPointer rdp_pointer; mfContext *mfc = (mfContext*) instance->context; @@ -908,7 +885,7 @@ BOOL mac_post_connect(freerdp* instance) rdp_pointer.SetNull = mf_Pointer_SetNull; rdp_pointer.SetDefault = mf_Pointer_SetDefault; - flags = CLRBUF_32BPP; + flags = CLRBUF_32BPP | CLRCONV_ALPHA; gdi_init(instance, flags, NULL); rdpGdi* gdi = instance->context->gdi; @@ -927,9 +904,6 @@ BOOL mac_post_connect(freerdp* instance) view->pasteboard_rd = [NSPasteboard generalPasteboard]; view->pasteboard_changecount = (int) [view->pasteboard_rd changeCount]; view->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:mfc->view selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; - - /* we want to be notified when window resizes */ - [[NSNotificationCenter defaultCenter] addObserver:mfc->view selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:nil]; return TRUE; } @@ -992,6 +966,11 @@ void mf_Pointer_New(rdpContext* context, rdpPointer* pointer) cursor_data = (BYTE*) malloc(rect.size.width * rect.size.height * 4); mrdpCursor->cursor_data = cursor_data; + if (pointer->xorBpp > 24) + { + freerdp_image_swap_color_order(pointer->xorMaskData, pointer->width, pointer->height); + } + freerdp_alpha_cursor_convert(cursor_data, pointer->xorMaskData, pointer->andMaskData, pointer->width, pointer->height, pointer->xorBpp, context->gdi->clrconv); @@ -1066,19 +1045,16 @@ void mf_Pointer_Set(rdpContext* context, rdpPointer* pointer) NSMutableArray* ma = view->cursors; - return; /* disable pointer until it is fixed */ - - if (!view->mouseInClientArea) - return; - for (MRDPCursor* cursor in ma) { if (cursor->pointer == pointer) { - [cursor->nsCursor set]; + [view setCursor:cursor->nsCursor]; return; } } + + NSLog(@"Cursor not found"); } /** ********************************************************************* @@ -1096,7 +1072,9 @@ void mf_Pointer_SetNull(rdpContext* context) void mf_Pointer_SetDefault(rdpContext* context) { - + mfContext* mfc = (mfContext*) context; + MRDPView* view = (MRDPView*) mfc->view; + [view setCursor:[NSCursor arrowCursor]]; } /** ********************************************************************* @@ -1152,10 +1130,10 @@ void mac_end_paint(rdpContext* context) for (i = 0; i < gdi->primary->hdc->hwnd->ninvalid; i++) { - drawRect.origin.x = gdi->primary->hdc->hwnd->cinvalid[i].x; - drawRect.origin.y = gdi->primary->hdc->hwnd->cinvalid[i].y; - drawRect.size.width = gdi->primary->hdc->hwnd->cinvalid[i].w; - drawRect.size.height = gdi->primary->hdc->hwnd->cinvalid[i].h; + drawRect.origin.x = gdi->primary->hdc->hwnd->cinvalid[i].x - 1; + drawRect.origin.y = gdi->primary->hdc->hwnd->cinvalid[i].y - 1; + drawRect.size.width = gdi->primary->hdc->hwnd->cinvalid[i].w + 1; + drawRect.size.height = gdi->primary->hdc->hwnd->cinvalid[i].h + 1; windows_to_apple_cords(mfc->view, &drawRect); [view setNeedsDisplayInRect:drawRect]; } @@ -1168,16 +1146,15 @@ void mac_end_paint(rdpContext* context) * called when update data is available ***********************************************************************/ -static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) +static void update_activity_cb(freerdp* instance) { int status; wMessage message; wMessageQueue* queue; - freerdp* instance = (freerdp*) info; status = 1; queue = freerdp_get_message_queue(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - + if (queue) { while (MessageQueue_Peek(queue, &message, TRUE)) @@ -1188,21 +1165,21 @@ static void update_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBack break; } } - - CFRelease(fdref); - register_update_fds(instance); + else + { + fprintf(stderr, "update_activity_cb: No queue!\n"); + } } /** ********************************************************************* * called when input data is available ***********************************************************************/ -static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) +static void input_activity_cb(freerdp* instance) { int status; wMessage message; - wMessageQueue* queue; - freerdp* instance = (freerdp*) info; + wMessageQueue* queue; status = 1; queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); @@ -1211,33 +1188,32 @@ static void input_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackT { while (MessageQueue_Peek(queue, &message, TRUE)) { - fprintf(stderr, "input_activity_cb: message %d\n", message.id); - status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE, &message); if (!status) break; } } - - CFRelease(fdref); - register_input_fds(instance); + else + { + fprintf(stderr, "input_activity_cb: No queue!\n"); + } } /** ********************************************************************* * called when data is available on a virtual channel ***********************************************************************/ -static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) +static void channel_activity_cb(freerdp* instance) { - wMessage* event; - freerdp* instance = (freerdp*) info; + wMessage* event; freerdp_channels_process_pending_messages(instance); event = freerdp_channels_pop_event(instance->context->channels); if (event) { - switch (GetMessageClass(event->id)) + fprintf(stderr, "channel_activity_cb: message %d\n", event->id); + switch (GetMessageClass(event->id)) { case CliprdrChannel_Class: process_cliprdr_event(instance, event); @@ -1246,90 +1222,6 @@ static void channel_activity_cb(CFFileDescriptorRef fdref, CFOptionFlags callBac freerdp_event_free(event); } - - CFRelease(fdref); - register_channels_fds(instance); -} - -/** ********************************************************************* - * setup callbacks for data availability on update message queue - ***********************************************************************/ - -int register_update_fds(freerdp* instance) -{ - int fd_update_event; - HANDLE update_event; - CFFileDescriptorRef fdref; - CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL }; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (instance->settings->AsyncUpdate) - { - update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE); - fd_update_event = GetEventFileDescriptor(update_event); - - fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_update_event, true, update_activity_cb, &fd_context); - CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); - view->run_loop_src_update = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_update, kCFRunLoopDefaultMode); - } - - return 0; -} - -/** ********************************************************************* - * setup callbacks for data availability on input message queue - ***********************************************************************/ - -int register_input_fds(freerdp* instance) -{ - int fd_input_event; - HANDLE input_event; - CFFileDescriptorRef fdref; - CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL }; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (instance->settings->AsyncInput) - { - input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); - fd_input_event = GetEventFileDescriptor(input_event); - - fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_input_event, true, input_activity_cb, &fd_context); - CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); - view->run_loop_src_input = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_input, kCFRunLoopDefaultMode); - } - - return 0; -} - -/** ********************************************************************* - * setup callbacks for data availability on channels - ***********************************************************************/ - -int register_channels_fds(freerdp* instance) -{ - int fd_channel_event; - HANDLE channel_event; - CFFileDescriptorRef fdref; - CFFileDescriptorContext fd_context = { 0, instance, NULL, NULL, NULL }; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (instance->settings->AsyncChannels) - { - channel_event = freerdp_channels_get_event_handle(instance); - fd_channel_event = GetEventFileDescriptor(channel_event); - - fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd_channel_event, true, channel_activity_cb, &fd_context); - CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack); - view->run_loop_src_channels = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), view->run_loop_src_channels, kCFRunLoopDefaultMode); - } - - return 0; } /** ********************************************************************* @@ -1567,20 +1459,12 @@ void cliprdr_send_supported_format_list(freerdp* instance) freerdp_channels_send_event(instance->context->channels, (wMessage*) event); } - -/** - * given a rect with 0,0 at the bottom left (apple cords) - * convert it to a rect with 0,0 at the top left (windows cords) - */ - -void apple_to_windows_cords(MRDPView* view, NSRect* r) -{ - r->origin.y = view->height - (r->origin.y + r->size.height); -} - /** * given a rect with 0,0 at the top left (windows cords) * convert it to a rect with 0,0 at the bottom left (apple cords) + * + * Note: the formula works for conversions in both directions. + * */ void windows_to_apple_cords(MRDPView* view, NSRect* r) diff --git a/client/Mac/cli/AppDelegate.h b/client/Mac/cli/AppDelegate.h index fe2671351..91439c06f 100644 --- a/client/Mac/cli/AppDelegate.h +++ b/client/Mac/cli/AppDelegate.h @@ -7,8 +7,8 @@ // #import -#import -#import +#import +#import @interface AppDelegate : NSObject { @@ -18,8 +18,9 @@ MRDPView* mrdpView; } +- (void) rdpConnectError: (NSString*) customMessage; + @property (assign) IBOutlet NSWindow *window; @property (assign) rdpContext *context; -@property (assign) IBOutlet MRDPView *mrdpView; @end diff --git a/client/Mac/cli/AppDelegate.m b/client/Mac/cli/AppDelegate.m index 1eb3d13c1..aec62be91 100644 --- a/client/Mac/cli/AppDelegate.m +++ b/client/Mac/cli/AppDelegate.m @@ -7,8 +7,13 @@ // #import "AppDelegate.h" -#import "MacFreeRDP-library/mfreerdp.h" -#import "MacFreeRDP-library/mf_client.h" +#import "MacFreeRDP/mfreerdp.h" +#import "MacFreeRDP/mf_client.h" + +static AppDelegate* _singleDelegate = nil; +void AppDelegate_EmbedWindowEventHandler(void* context, EmbedWindowEventArgs* e); +void AppDelegate_ConnectionResultEventHandler(void* context, ConnectionResultEventArgs* e); +void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e); @implementation AppDelegate @@ -19,7 +24,6 @@ @synthesize window = window; -@synthesize mrdpView = mrdpView; @synthesize context = context; @@ -28,6 +32,7 @@ int status; mfContext* mfc; + _singleDelegate = self; [self CreateContext]; status = [self ParseCommandLineArguments]; @@ -41,6 +46,10 @@ } else { + PubSub_SubscribeConnectionResult(context->pubSub, AppDelegate_ConnectionResultEventHandler); + PubSub_SubscribeErrorInfo(context->pubSub, AppDelegate_ErrorInfoEventHandler); + PubSub_SubscribeEmbedWindow(context->pubSub, AppDelegate_EmbedWindowEventHandler); + freerdp_client_start(context); } } @@ -48,6 +57,7 @@ - (void) applicationWillTerminate:(NSNotification*)notification { [mrdpView releaseResources]; + _singleDelegate = nil; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender @@ -103,4 +113,92 @@ context = nil; } + +/** ********************************************************************* + * called when we fail to connect to a RDP server - Make sure this is called from the main thread. + ***********************************************************************/ + +- (void) rdpConnectError : (NSString*) withMessage +{ + NSString* message = withMessage ? withMessage : @"Error connecting to server"; + + NSAlert *alert = [[NSAlert alloc] init]; + [alert setMessageText:message]; + [alert beginSheetModalForWindow:[self window] + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; +} + + +/** ********************************************************************* + * just a terminate selector for above call + ***********************************************************************/ + +- (void) alertDidEnd:(NSAlert *)a returnCode:(NSInteger)rc contextInfo:(void *)ci +{ + [NSApp terminate:nil]; +} + + @end + +void AppDelegate_EmbedWindowEventHandler(void* ctx, EmbedWindowEventArgs* e) +{ + rdpContext* context = (rdpContext*) ctx; + + if (_singleDelegate) + { + mfContext* mfc = (mfContext*) context; + _singleDelegate->mrdpView = mfc->view; + + if (_singleDelegate->window) + { + [[_singleDelegate->window contentView] addSubview:mfc->view]; + } + } +} + +/** ********************************************************************* + * On connection error, display message and quit application + ***********************************************************************/ + +void AppDelegate_ConnectionResultEventHandler(void* ctx, ConnectionResultEventArgs* e) +{ + NSLog(@"ConnectionResult event result:%d\n", e->result); + if (_singleDelegate) + { + if (e->result != 0) + { + NSString* message = nil; + if (connectErrorCode == AUTHENTICATIONERROR) + { + message = [NSString stringWithFormat:@"%@:\n%@", message, @"Authentication failure, check credentials."]; + } + + + // Making sure this should be invoked on the main UI thread. + [_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:FALSE]; + [message release]; + } + } +} + +void AppDelegate_ErrorInfoEventHandler(void* ctx, ErrorInfoEventArgs* e) +{ + NSLog(@"ErrorInfo event code:%d\n", e->code); + if (_singleDelegate) + { + // Retrieve error message associated with error code + NSString* message = nil; + if (e->code != ERRINFO_NONE) + { + const char* errorMessage = freerdp_get_error_info_string(e->code); + message = [[NSString alloc] initWithUTF8String:errorMessage]; + } + + // Making sure this should be invoked on the main UI thread. + [_singleDelegate performSelectorOnMainThread:@selector(rdpConnectError:) withObject:message waitUntilDone:TRUE]; + [message release]; + } +} \ No newline at end of file diff --git a/client/Mac/cli/CMakeLists.txt b/client/Mac/cli/CMakeLists.txt index 46643227d..e8033e2f5 100644 --- a/client/Mac/cli/CMakeLists.txt +++ b/client/Mac/cli/CMakeLists.txt @@ -1,15 +1,14 @@ -project(MacFreeRDP-client) + +project(MacFreeRDP) set(MODULE_NAME "MacFreeRDP") set(MODULE_OUTPUT_NAME "MacFreeRDP") set(MODULE_PREFIX "FREERDP_CLIENT_MAC_CLIENT") -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mmacosx-version-min=10.5") # Import libraries find_library(FOUNDATION_LIBRARY Foundation) find_library(COCOA_LIBRARY Cocoa) find_library(APPKIT_LIBRARY AppKit) -#find_library(FREERDP_LIBRARY NAMES MacFreeRDP PATHS ${CMAKE_CURRENT_BINARY_DIR}/../${CONFIGURATION}) set(MACOSX_BUNDLE_INFO_STRING "MacFreeRDP") set(MACOSX_BUNDLE_ICON_FILE "FreeRDP.icns") @@ -27,28 +26,32 @@ set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication") mark_as_advanced(COCOA_LIBRARY FOUNDATION_LIBRARY APPKIT_LIBRARY) set(APP_TYPE MACOSX_BUNDLE) -# OS X Interface Builder files -file(GLOB ${MODULE_NAME}_XIBS *.xib) +set(${MODULE_PREFIX}_XIBS MainMenu.xib) -set(${MODULE_NAME}_RESOURCES ${MACOSX_BUNDLE_ICON_FILE}) +set(${MODULE_PREFIX}_SOURCES "") + +set(${MODULE_PREFIX}_OBJECTIVE_SOURCES + main.m + AppDelegate.m) + +list(APPEND ${MODULE_PREFIX}_SOURCES ${${MODULE_PREFIX}_OBJECTIVE_SOURCES}) + +set(${MODULE_PREFIX}_HEADERS + AppDelegate.h) + +set(${MODULE_PREFIX}_RESOURCES ${MACOSX_BUNDLE_ICON_FILE}) # Include XIB file in Xcode resources. if("${CMAKE_GENERATOR}" MATCHES "Xcode") message(STATUS "Adding Xcode XIB resources for ${MODULE_NAME}") - set(${MODULE_NAME}_RESOURCES ${${MODULE_NAME}_RESOURCES} ${${MODULE_NAME}_XIBS}) -endif("${CMAKE_GENERATOR}" MATCHES "Xcode") - -# Headers -file(GLOB ${MODULE_NAME}_HEADERS *.h) - -# Source -file(GLOB ${MODULE_NAME}_SOURCES *.m) + set(${MODULE_PREFIX}_RESOURCES ${${MODULE_PREFIX}_RESOURCES} ${${MODULE_PREFIX}_XIBS}) +endif() add_executable(${MODULE_NAME} ${APP_TYPE} - ${${MODULE_NAME}_HEADERS} - ${${MODULE_NAME}_SOURCES} - ${${MODULE_NAME}_RESOURCES}) + ${${MODULE_PREFIX}_HEADERS} + ${${MODULE_PREFIX}_SOURCES} + ${${MODULE_PREFIX}_RESOURCES}) set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "${MODULE_OUTPUT_NAME}") @@ -56,14 +59,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "${MODULE_OUTPUT_NAM configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Info.plist ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) # This allows for automatic xib to nib ibitool -set_target_properties(${MODULE_NAME} PROPERTIES RESOURCE "${${MODULE_NAME}_RESOURCES}") - -# Automatic ref counting -# temporary turn off for x86_64 build issue -# set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES) - -# Support for automatic reference counting requires non-fragile abi. -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-nonfragile-abi") +set_target_properties(${MODULE_NAME} PROPERTIES RESOURCE "${${MODULE_PREFIX}_RESOURCES}") # Tell the compiler where to look for the FreeRDP framework set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -F../") @@ -72,8 +68,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -F../") set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS "${XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS} ${CMAKE_CURRENT_BINARY_DIR}/../$(CONFIGURATION)") -set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_ARCHS "$(NATIVE_ARCH_ACTUAL)") - # Set the info plist to the custom instance set_target_properties(${MODULE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) @@ -86,7 +80,7 @@ set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Mac") add_custom_command(TARGET ${MODULE_NAME} POST_BUILD COMMAND mkdir ARGS -p ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/Frameworks COMMAND ditto ${CMAKE_CURRENT_BINARY_DIR}/../$(CONFIGURATION)/MacFreeRDP.framework ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/Frameworks/MacFreeRDP.framework - COMMAND install_name_tool -change "@executable_path/../../Frameworks/MacFreeRDP.framework/Versions/1.1.0/MacFreeRDP" + COMMAND install_name_tool -change "@executable_path/../Frameworks/MacFreeRDP.framework/Versions/${MAC_OS_X_BUNDLE_BUNDLE_VERSION}/MacFreeRDP" "@executable_path/../Frameworks/MacFreeRDP.framework/Versions/Current/MacFreeRDP" "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/MacOS/${MODULE_NAME}" COMMENT Setting install name for MacFreeRDP) @@ -106,13 +100,13 @@ if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") add_custom_command(TARGET ${MODULE_NAME} PRE_BUILD COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${MODULE_OUTPUT_NAME}.app/Contents/Resources) # Compile the .xib files using the 'ibtool' program with the destination being the app package - foreach(xib ${${MODULE_NAME}_XIBS}) + foreach(xib ${${MODULE_PREFIX}_XIBS}) get_filename_component(XIB_WE ${xib} NAME_WE) add_custom_command (TARGET ${MODULE_NAME} POST_BUILD COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text - --compile ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${MODULE_OUTPUT_NAME}.app/Contents/Resources/${XIB_WE}.nib ${xib} + --compile ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${MODULE_OUTPUT_NAME}.app/Contents/Resources/${XIB_WE}.nib ${CMAKE_CURRENT_SOURCE_DIR}/${xib} COMMENT "Compiling ${xib}") endforeach() -endif("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") +endif() diff --git a/client/Mac/cli/MainMenu.xib b/client/Mac/cli/MainMenu.xib index 90e992462..65e72b118 100755 --- a/client/Mac/cli/MainMenu.xib +++ b/client/Mac/cli/MainMenu.xib @@ -2,18 +2,16 @@ 1070 - 12D78 + 12E55 3084 - 1187.37 + 1187.39 626.00 com.apple.InterfaceBuilder.CocoaPlugin 3084 - IBNSLayoutConstraint NSCustomObject - NSCustomView NSMenu NSMenuItem NSView @@ -257,24 +255,12 @@ 256 - - - - 268 - {1024, 768} - - - - _NS:9 - MRDPView - - + {1024, 768} - - + - {{0, 0}, {1440, 878}} + {{0, 0}, {1920, 1178}} {1024, 790} {1024, 790} 128 @@ -369,14 +355,6 @@ 493 - - - mrdpView - - - - 569 - window @@ -551,73 +529,7 @@ 372 - - - - - 6 - 0 - - 6 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - 5 - 0 - - 5 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - 4 - 0 - - 4 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - - - 3 - 0 - - 3 - 1 - - 0.0 - - 1000 - - 8 - 29 - 3 - - + @@ -657,31 +569,6 @@ - - 551 - - - - - 561 - - - - - 562 - - - - - 563 - - - - - 564 - - - @@ -706,12 +593,6 @@ com.apple.InterfaceBuilder.CocoaPlugin {{380, 496}, {480, 360}} - - - - - - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -720,13 +601,7 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -738,48 +613,7 @@ 570 - - - - AppDelegate - NSObject - - MRDPView - NSWindow - - - - mrdpView - MRDPView - - - window - NSWindow - - - - IBProjectSource - ./Classes/AppDelegate.h - - - - MRDPView - NSView - - IBProjectSource - ./Classes/MRDPView.h - - - - NSLayoutConstraint - NSObject - - IBProjectSource - ./Classes/NSLayoutConstraint.h - - - - + 0 IBCocoaFramework diff --git a/client/Mac/mf_client.m b/client/Mac/mf_client.m index 20aa3ce01..cf830d3c7 100755 --- a/client/Mac/mf_client.m +++ b/client/Mac/mf_client.m @@ -25,6 +25,7 @@ #include #include #include +#import "MRDPView.h" /** * Client Interface @@ -46,6 +47,13 @@ int mfreerdp_client_start(rdpContext* context) MRDPView* view; mfContext* mfc = (mfContext*) context; + if (mfc->view == NULL) + { + // view not specified beforehand. Create view dynamically + mfc->view = [[MRDPView alloc] initWithFrame : NSMakeRect(0, 0, context->settings->DesktopWidth, context->settings->DesktopHeight)]; + mfc->view_ownership = TRUE; + } + view = (MRDPView*) mfc->view; [view rdpStart:context]; @@ -60,19 +68,40 @@ int mfreerdp_client_stop(rdpContext* context) { wMessageQueue* queue; queue = freerdp_get_message_queue(context->instance, FREERDP_UPDATE_MESSAGE_QUEUE); - MessageQueue_PostQuit(queue, 0); + if (queue) + { + MessageQueue_PostQuit(queue, 0); + } } - - if (context->settings->AsyncInput) + else if (context->settings->AsyncInput) { wMessageQueue* queue; queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_QUEUE); - MessageQueue_PostQuit(queue, 0); - } + if (queue) + { + MessageQueue_PostQuit(queue, 0); + } + } else { mfc->disconnect = TRUE; } + + if (mfc->thread) + { + SetEvent(mfc->stopEvent); + WaitForSingleObject(mfc->thread, INFINITE); + CloseHandle(mfc->thread); + mfc->thread = NULL; + } + + if (mfc->view_ownership) + { + MRDPView* view = (MRDPView*) mfc->view; + [view releaseResources]; + [view release]; + mfc->view = nil; + } return 0; } @@ -84,12 +113,19 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context) mfc = (mfContext*) instance->context; - context->channels = freerdp_channels_new(); + mfc->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + context->instance->PreConnect = mac_pre_connect; + context->instance->PostConnect = mac_post_connect; + context->instance->ReceiveChannelData = mac_receive_channel_data; + context->instance->Authenticate = mac_authenticate; + + context->channels = freerdp_channels_new(); settings = instance->settings; - settings->AsyncUpdate = TRUE; - // TODO settings->AsyncInput = TRUE; + settings->AsyncUpdate = TRUE; + settings->AsyncInput = TRUE; settings->AsyncChannels = TRUE; settings->AsyncTransport = TRUE; settings->RedirectClipboard = TRUE; diff --git a/client/Mac/mfreerdp.h b/client/Mac/mfreerdp.h index 02b0272e2..52e7be122 100644 --- a/client/Mac/mfreerdp.h +++ b/client/Mac/mfreerdp.h @@ -28,6 +28,7 @@ struct mf_context DEFINE_RDP_CLIENT_COMMON(); void* view; + BOOL view_ownership; // TRUE indicates that the window was created and should be freed by the API. int width; int height; @@ -43,6 +44,7 @@ struct mf_context int client_height; HANDLE keyboardThread; + HANDLE stopEvent; HGDI_DC hdc; UINT16 srcBpp; diff --git a/client/Windows/CMakeLists.txt b/client/Windows/CMakeLists.txt index 0f2b26d65..f32422cd3 100644 --- a/client/Windows/CMakeLists.txt +++ b/client/Windows/CMakeLists.txt @@ -63,8 +63,10 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) if(WITH_CLIENT_INTERFACE) + if (NOT WITH_WAYK) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) add_subdirectory(cli) + endif() else() install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) endif() diff --git a/client/Windows/wf_gdi.c b/client/Windows/wf_gdi.c index 41fae28d0..15e9b4363 100644 --- a/client/Windows/wf_gdi.c +++ b/client/Windows/wf_gdi.c @@ -575,14 +575,14 @@ void wf_gdi_surface_bits(wfContext* wfc, SURFACE_BITS_COMMAND* surface_bits_comm message = rfx_process_message(rfx_context, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); /* blit each tile */ - for (i = 0; i < message->num_tiles; i++) + for (i = 0; i < message->numTiles; i++) { tx = message->tiles[i]->x + surface_bits_command->destLeft; ty = message->tiles[i]->y + surface_bits_command->destTop; freerdp_image_convert(message->tiles[i]->data, wfc->tile->pdata, 64, 64, 32, 32, wfc->clrconv); - for (j = 0; j < message->num_rects; j++) + for (j = 0; j < message->numRects; j++) { wf_set_clip_rgn(wfc, surface_bits_command->destLeft + message->rects[j].x, @@ -596,7 +596,7 @@ void wf_gdi_surface_bits(wfContext* wfc, SURFACE_BITS_COMMAND* surface_bits_comm wf_set_null_clip_rgn(wfc); /* invalidate regions */ - for (i = 0; i < message->num_rects; i++) + for (i = 0; i < message->numRects; i++) { tx = surface_bits_command->destLeft + message->rects[i].x; ty = surface_bits_command->destTop + message->rects[i].y; @@ -618,7 +618,7 @@ void wf_gdi_surface_bits(wfContext* wfc, SURFACE_BITS_COMMAND* surface_bits_comm bitmap_info.bmiHeader.biCompression = BI_RGB; SetDIBitsToDevice(wfc->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop, surface_bits_command->width, surface_bits_command->height, 0, 0, 0, surface_bits_command->height, - nsc_context->bmpdata, &bitmap_info, DIB_RGB_COLORS); + nsc_context->BitmapData, &bitmap_info, DIB_RGB_COLORS); wf_invalidate_region(wfc, surface_bits_command->destLeft, surface_bits_command->destTop, surface_bits_command->width, surface_bits_command->height); } @@ -664,8 +664,8 @@ void wf_gdi_register_update_callbacks(rdpUpdate* update) { rdpPrimaryUpdate* primary = update->primary; - update->Palette = wf_gdi_palette_update; - update->SetBounds = wf_gdi_set_bounds; + update->Palette = (pPalette) wf_gdi_palette_update; + update->SetBounds = (pSetBounds) wf_gdi_set_bounds; primary->DstBlt = (pDstBlt) wf_gdi_dstblt; primary->PatBlt = (pPatBlt) wf_gdi_patblt; @@ -690,8 +690,8 @@ void wf_gdi_register_update_callbacks(rdpUpdate* update) primary->EllipseSC = NULL; primary->EllipseCB = NULL; - update->SurfaceBits = wf_gdi_surface_bits; - update->SurfaceFrameMarker = wf_gdi_surface_frame_marker; + update->SurfaceBits = (pSurfaceBits) wf_gdi_surface_bits; + update->SurfaceFrameMarker = (pSurfaceFrameMarker) wf_gdi_surface_frame_marker; } void wf_update_canvas_diff(wfContext* wfc) diff --git a/client/X11/.gitignore b/client/X11/.gitignore new file mode 100644 index 000000000..de7ef2209 --- /dev/null +++ b/client/X11/.gitignore @@ -0,0 +1,2 @@ +*.xml +generate_argument_docbook diff --git a/client/X11/CMakeLists.txt b/client/X11/CMakeLists.txt index 56dd96bdb..907200733 100644 --- a/client/X11/CMakeLists.txt +++ b/client/X11/CMakeLists.txt @@ -2,6 +2,7 @@ # FreeRDP X11 Client # # Copyright 2012 Marc-Andre Moreau +# Copyright 2013 Corey Clayton # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,7 +19,7 @@ set(MODULE_NAME "xfreerdp-client") set(MODULE_PREFIX "FREERDP_CLIENT_X11_CONTROL") -include(FindXmlto) +include(FindDocBookXSL) include_directories(${X11_INCLUDE_DIRS}) set(${MODULE_PREFIX}_SRCS @@ -28,6 +29,8 @@ set(${MODULE_PREFIX}_SRCS xf_rail.h xf_tsmf.c xf_tsmf.h + xf_input.c + xf_input.h xf_event.c xf_event.h xf_input.c @@ -65,18 +68,55 @@ set(${MODULE_PREFIX}_LIBS ${CMAKE_DL_LIBS}) if(WITH_MANPAGES) - if(XMLTO_FOUND) + find_program( XSLTPROC_EXECUTABLE NAMES xsltproc) + + if(DOCBOOKXSL_FOUND AND XSLTPROC_EXECUTABLE) + + # We need the variable ${MAN_TODAY} to contain the current date in ISO + # format to replace it in the configure_file step. + include(today) + + TODAY(MAN_TODAY) + + configure_file(xfreerdp.1.xml.in xfreerdp.1.xml @ONLY IMMEDIATE) + + add_executable(generate_argument_docbook generate_argument_docbook.c) + + set(GAD_LIBS freerdp-client) + + set_complex_link_libraries(VARIABLE GAD_LIBS MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-utils) + + set_complex_link_libraries(VARIABLE GAD_LIBS MONOLITHIC ${MONOLITHIC_BUILD} + MODULE freerdp + MODULES freerdp-core freerdp-utils) + + message(WARNING "GAD_LIBS: ${GAD_LIBS}") + + target_link_libraries(generate_argument_docbook ${GAD_LIBS}) + add_custom_command(OUTPUT xfreerdp.1 - COMMAND ${XMLTO_EXECUTABLE} man ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp.1.xml - DEPENDS xfreerdp.1.xml) + COMMAND generate_argument_docbook + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-channels.1.xml ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-examples.1.xml ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${XSLTPROC_EXECUTABLE} ${DOCBOOKXSL_DIR}/manpages/docbook.xsl xfreerdp.1.xml + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/xfreerdp.1.xml + ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-examples.1.xml + ${CMAKE_CURRENT_SOURCE_DIR}/xfreerdp-channels.1.xml + generate_argument_docbook) add_custom_target(xfreerdp.manpage ALL DEPENDS xfreerdp.1) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/xfreerdp.1 DESTINATION share/man/man1) - else(XMLTO_FOUND) - message(WARNING "WITH_MANPAGES was set, but xmlto was not found. man-pages will not be installed") - endif(XMLTO_FOUND) + else() + message(WARNING "WITH_MANPAGES was set, but xsltproc was not found. man-pages will not be installed") + endif() endif(WITH_MANPAGES) set(XSHM_FEATURE_TYPE "REQUIRED") @@ -101,11 +141,11 @@ set(XV_FEATURE_DESCRIPTION "X11 video extension") set(XI_FEATURE_TYPE "RECOMMENDED") set(XI_FEATURE_PURPOSE "input") -set(XI_FEATURE_DESCRIPTION "X11 input extension") +set(XI_FEATURE_DESCRIPTION "X11 input extension") set(XRENDER_FEATURE_TYPE "RECOMMENDED") set(XRENDER_FEATURE_PURPOSE "rendering") -set(XRENDER_FEATURE_DESCRIPTION "X11 render extension") +set(XRENDER_FEATURE_DESCRIPTION "X11 render extension") find_feature(XShm ${XSHM_FEATURE_TYPE} ${XSHM_FEATURE_PURPOSE} ${XSHM_FEATURE_DESCRIPTION}) find_feature(Xinerama ${XINERAMA_FEATURE_TYPE} ${XINERAMA_FEATURE_PURPOSE} ${XINERAMA_FEATURE_DESCRIPTION}) diff --git a/client/X11/generate_argument_docbook.c b/client/X11/generate_argument_docbook.c new file mode 100644 index 000000000..0c1da21a8 --- /dev/null +++ b/client/X11/generate_argument_docbook.c @@ -0,0 +1,177 @@ + +#include +#include +#include + +#include + +/* We need to include the command line c file to get access to + * the argument struct. */ +#include "../common/cmdline.c" + +LPSTR tmp = NULL; + +LPCSTR tr_esc_str(LPCSTR arg) +{ + size_t cs = 0, x, ds; + size_t s; + + if( NULL == arg ) + return NULL; + + s = strlen(arg); + + /* Find trailing whitespaces */ + while( (s > 0) && isspace(arg[s-1])) + s--; + + /* Prepare a initial buffer with the size of the result string. */ + tmp = malloc(s * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not allocate string buffer."); + exit(-2); + } + + /* Copy character for character and check, if it is necessary to escape. */ + ds = s + 1; + for(x=0; x': + ds += 3; + tmp = realloc(tmp, ds * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not reallocate string buffer."); + exit(-4); + } + tmp[cs++] = '&'; + tmp[cs++] = 'g'; + tmp[cs++] = 't'; + tmp[cs++] = ';'; + break; + case '\'': + ds += 5; + tmp = realloc(tmp, ds * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not reallocate string buffer."); + exit(-5); + } + tmp[cs++] = '&'; + tmp[cs++] = 'a'; + tmp[cs++] = 'p'; + tmp[cs++] = 'o'; + tmp[cs++] = 's'; + tmp[cs++] = ';'; + break; + case '"': + ds += 5; + tmp = realloc(tmp, ds * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not reallocate string buffer."); + exit(-6); + } + tmp[cs++] = '&'; + tmp[cs++] = 'q'; + tmp[cs++] = 'u'; + tmp[cs++] = 'o'; + tmp[cs++] = 't'; + tmp[cs++] = ';'; + break; + case '&': + ds += 4; + tmp = realloc(tmp, ds * sizeof(LPCSTR)); + if( NULL == tmp ) + { + fprintf(stderr, "Could not reallocate string buffer."); + exit(-7); + } + tmp[cs++] = '&'; + tmp[cs++] = 'a'; + tmp[cs++] = 'm'; + tmp[cs++] = 'p'; + tmp[cs++] = ';'; + break; + default: + tmp[cs++] = arg[x]; + break; + } + + /* Assure, the string is '\0' terminated. */ + tmp[ds-1] = '\0'; + } + + return tmp; +} + +int main(int argc, char *argv[]) +{ + size_t elements = sizeof(args)/sizeof(args[0]); + size_t x; + const char *fname = "xfreerdp-argument.1.xml"; + FILE *fp = NULL; + + /* Open output file for writing, truncate if existing. */ + fp = fopen(fname, "w"); + if( NULL == fp ) + { + fprintf(stderr, "Could not open '%s' for writing.", fname); + return -1; + } + + /* The tag used as header in the manpage */ + fprintf(fp, "\n"); + fprintf(fp, "\tOptions\n"); + fprintf(fp, "\t\t\n"); + + /* Iterate over argument struct and write data to docbook 4.5 + * compatible XML */ + if( elements < 2 ) + { + fprintf(stderr, "The argument array 'args' is empty, writing an empty file."); + elements = 1; + } + + for(x=0; x\n"); + if( COMMAND_LINE_VALUE_REQUIRED == arg->Flags ) + fprintf(fp, "\t\t\t\t %s\n", tr_esc_str(arg->Name), tr_esc_str(arg->Format) ); + else + fprintf(fp, "\t\t\t\t\n", tr_esc_str(arg->Name) ); + fprintf(fp, "\t\t\t\t\n"); + fprintf(fp, "\t\t\t\t\t%s\n", tr_esc_str(arg->Text)); + + fprintf(fp, "\t\t\t\t\n"); + fprintf(fp, "\t\t\t\n"); + } + + fprintf(fp, "\t\t\n"); + fprintf(fp, "\t\n"); + fclose(fp); + + if(NULL != tmp) + free(tmp); + + return 0; +} + diff --git a/client/X11/xf_channels.c b/client/X11/xf_channels.c index 91dda0b8e..24325046e 100644 --- a/client/X11/xf_channels.c +++ b/client/X11/xf_channels.c @@ -26,19 +26,17 @@ #include "xf_client.h" #include "xfreerdp.h" -int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface) +void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) { - xfContext* xfc = (xfContext*) instance->context; + xfContext* xfc = (xfContext*) context; - if (strcmp(name, RDPEI_DVC_CHANNEL_NAME) == 0) + if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { - xfc->rdpei = (RdpeiClientContext*) pInterface; + xfc->rdpei = (RdpeiClientContext*) e->pInterface; } - - return 0; } -int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface) +void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) { - return 0; + } diff --git a/client/X11/xf_channels.h b/client/X11/xf_channels.h index 1aeaf1a66..bb52d5e52 100644 --- a/client/X11/xf_channels.h +++ b/client/X11/xf_channels.h @@ -27,4 +27,7 @@ int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface); int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface); +void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e); +void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e); + #endif diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 7e958feeb..5ad3f4f04 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -3,6 +3,7 @@ * X11 Client Interface * * Copyright 2013 Marc-Andre Moreau + * Copyright 2013 Corey Clayton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +25,14 @@ #include #include +#ifdef WITH_XRENDER +#include +#endif + +#ifdef WITH_XI +#include +#endif + #ifdef WITH_XCURSOR #include #endif @@ -73,6 +82,7 @@ #include #include #include +#include #include "xf_gdi.h" #include "xf_rail.h" @@ -83,14 +93,51 @@ #include "xf_monitor.h" #include "xf_graphics.h" #include "xf_keyboard.h" +#include "xf_input.h" #include "xf_channels.h" - #include "xfreerdp.h" static long xv_port = 0; static const size_t password_size = 512; -void xf_draw_screen_scaled(xfContext* xfc) +void xf_transform_window(xfContext* xfc) +{ + int ret; + int w; + int h; + long supplied; + Atom hints_atom; + XSizeHints* size_hints = NULL; + + hints_atom = XInternAtom(xfc->display, "WM_SIZE_HINTS", 1); + + ret = XGetWMSizeHints(xfc->display, xfc->window->handle, size_hints, &supplied, hints_atom); + + if(ret == 0) + size_hints = XAllocSizeHints(); + + w = (xfc->originalWidth * xfc->settings->ScalingFactor) + xfc->offset_x; + h = (xfc->originalHeight * xfc->settings->ScalingFactor) + xfc->offset_y; + + if(w < 1) + w = 1; + + if(h < 1) + h = 1; + + if (size_hints) + { + size_hints->flags |= PMinSize | PMaxSize; + size_hints->min_width = size_hints->max_width = w; + size_hints->min_height = size_hints->max_height = h; + XSetWMNormalHints(xfc->display, xfc->window->handle, size_hints); + XResizeWindow(xfc->display, xfc->window->handle, w, h); + + XFree(size_hints); + } +} + +void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scale) { #ifdef WITH_XRENDER XTransform transform; @@ -98,6 +145,7 @@ void xf_draw_screen_scaled(xfContext* xfc) Picture primaryPicture; XRenderPictureAttributes pa; XRenderPictFormat* picFormat; + XRectangle xr; picFormat = XRenderFindStandardFormat(xfc->display, PictStandardRGB24); pa.subwindow_mode = IncludeInferiors; @@ -114,11 +162,38 @@ void xf_draw_screen_scaled(xfContext* xfc) transform.matrix[2][0] = XDoubleToFixed(0); transform.matrix[2][1] = XDoubleToFixed(0); - transform.matrix[2][2] = XDoubleToFixed(xfc->scale); + transform.matrix[2][2] = XDoubleToFixed(xfc->settings->ScalingFactor); + + if( (w != 0) && (h != 0) ) + { + + if(scale == TRUE) + { + xr.x = x * xfc->settings->ScalingFactor; + xr.y = y * xfc->settings->ScalingFactor; + xr.width = (w+1) * xfc->settings->ScalingFactor; + xr.height = (h+1) * xfc->settings->ScalingFactor; + } + else + { + xr.x = x; + xr.y = y; + xr.width = w; + xr.height = h; + } + + XRenderSetPictureClipRectangles(xfc->display, primaryPicture, 0, 0, &xr, 1); + } XRenderSetPictureTransform(xfc->display, primaryPicture, &transform); - XRenderComposite(xfc->display, PictOpSrc, primaryPicture, 0, windowPicture, 0, 0, 0, 0, 0, 0, xfc->currentWidth, xfc->currentHeight); + + XRenderComposite(xfc->display, PictOpSrc, primaryPicture, 0, windowPicture, 0, 0, 0, 0, xfc->offset_x, xfc->offset_y, xfc->currentWidth, xfc->currentHeight); + + XRenderFreePicture(xfc->display, primaryPicture); + XRenderFreePicture(xfc->display, windowPicture); + #endif + } void xf_sw_begin_paint(rdpContext* context) @@ -153,9 +228,9 @@ void xf_sw_end_paint(rdpContext* context) XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); - if (xfc->scale != 1.0) + if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) ) { - xf_draw_screen_scaled(xfc); + xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } else { @@ -184,12 +259,13 @@ void xf_sw_end_paint(rdpContext* context) y = cinvalid[i].y; w = cinvalid[i].w; h = cinvalid[i].h; - + + //combine xfc->primary with xfc->image XPutImage(xfc->display, xfc->primary, xfc->gc, xfc->image, x, y, x, y, w, h); - if (xfc->scale != 1.0) + if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) ) { - xf_draw_screen_scaled(xfc); + xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } else { @@ -271,12 +347,12 @@ void xf_hw_end_paint(rdpContext* context) y = xfc->hdc->hwnd->invalid->y; w = xfc->hdc->hwnd->invalid->w; h = xfc->hdc->hwnd->invalid->h; - + xf_lock_x11(xfc, FALSE); - if (xfc->scale != 1.0) + if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) ) { - xf_draw_screen_scaled(xfc); + xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } else { @@ -305,10 +381,10 @@ void xf_hw_end_paint(rdpContext* context) y = cinvalid[i].y; w = cinvalid[i].w; h = cinvalid[i].h; - - if (xfc->scale != 1.0) + + if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) ) { - xf_draw_screen_scaled(xfc); + xf_draw_screen_scaled(xfc, x, y, w, h, TRUE); } else { @@ -666,8 +742,11 @@ BOOL xf_pre_connect(freerdp* instance) settings = instance->settings; channels = instance->context->channels; - instance->OnChannelConnected = xf_on_channel_connected; - instance->OnChannelDisconnected = xf_on_channel_disconnected; + PubSub_SubscribeChannelConnected(instance->context->pubSub, + (pChannelConnectedEventHandler) xf_OnChannelConnectedEventHandler); + + PubSub_SubscribeChannelDisconnected(instance->context->pubSub, + (pChannelDisconnectedEventHandler) xf_OnChannelDisconnectedEventHandler); freerdp_client_load_addins(channels, instance->settings); @@ -829,7 +908,10 @@ BOOL xf_post_connect(freerdp* instance) xfc->originalHeight = settings->DesktopHeight; xfc->currentWidth = xfc->originalWidth; xfc->currentHeight = xfc->originalWidth; - xfc->scale = 1.0; + xfc->settings->ScalingFactor = 1.0; + + xfc->offset_x = 0; + xfc->offset_y = 0; xfc->width = settings->DesktopWidth; xfc->height = settings->DesktopHeight; @@ -1480,6 +1562,8 @@ void* xf_thread(void* param) gdi_free(instance); ExitThread(exit_code); + + return NULL; } DWORD xf_exit_code_from_disconnect_reason(DWORD reason) @@ -1520,6 +1604,66 @@ void xf_TerminateEventHandler(rdpContext* context, TerminateEventArgs* e) } } +void xf_ParamChangeEventHandler(rdpContext* context, ParamChangeEventArgs* e) +{ + + xfContext* xfc = (xfContext*) context; + + switch (e->id) + { + case FreeRDP_ScalingFactor: + + xfc->currentWidth = xfc->originalWidth * xfc->settings->ScalingFactor; + xfc->currentHeight = xfc->originalHeight * xfc->settings->ScalingFactor; + + xf_transform_window(xfc); + + { + ResizeWindowEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; + e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; + PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); + } + xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE); + + break; + + default: + break; + } +} + +void xf_ScalingFactorChangeEventHandler(rdpContext* context, ScalingFactorChangeEventArgs* e) +{ + xfContext* xfc = (xfContext*) context; + + xfc->settings->ScalingFactor += e->ScalingFactor; + + if (xfc->settings->ScalingFactor > 1.2) + xfc->settings->ScalingFactor = 1.2; + if (xfc->settings->ScalingFactor < 0.8) + xfc->settings->ScalingFactor = 0.8; + + + xfc->currentWidth = xfc->originalWidth * xfc->settings->ScalingFactor; + xfc->currentHeight = xfc->originalHeight * xfc->settings->ScalingFactor; + + xf_transform_window(xfc); + + { + ResizeWindowEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; + e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; + PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); + } + xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE); + +} + /** * Client Interface */ @@ -1573,28 +1717,6 @@ int xfreerdp_client_stop(rdpContext* context) return 0; } -double freerdp_client_get_scale(rdpContext* context) -{ - xfContext* xfc = (xfContext*) context; - return xfc->scale; -} - -void freerdp_client_reset_scale(rdpContext* context) -{ - ResizeWindowEventArgs e; - xfContext* xfc = (xfContext*) context; - - xfc->scale = 1.0; - XResizeWindow(xfc->display, xfc->window->handle, xfc->originalWidth * xfc->scale, xfc->originalHeight * xfc->scale); - - EventArgsInit(&e, "xfreerdp"); - e.width = (int) xfc->originalWidth * xfc->scale; - e.height = (int) xfc->originalHeight * xfc->scale; - PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); - - xf_draw_screen_scaled(xfc); -} - int xfreerdp_client_new(freerdp* instance, rdpContext* context) { xfContext* xfc; @@ -1643,6 +1765,9 @@ int xfreerdp_client_new(freerdp* instance, rdpContext* context) settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; PubSub_SubscribeTerminate(context->pubSub, (pTerminateEventHandler) xf_TerminateEventHandler); + PubSub_SubscribeParamChange(context->pubSub, (pParamChangeEventHandler) xf_ParamChangeEventHandler); + PubSub_SubscribeScalingFactorChange(context->pubSub, (pScalingFactorChangeEventHandler) xf_ScalingFactorChangeEventHandler); + return 0; } diff --git a/client/X11/xf_client.h b/client/X11/xf_client.h index 604e46700..dec4876f2 100644 --- a/client/X11/xf_client.h +++ b/client/X11/xf_client.h @@ -44,6 +44,7 @@ extern "C" { * Client Interface */ + FREERDP_API int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints); #ifdef __cplusplus diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index bf64b63b4..7205a7b67 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -32,6 +32,7 @@ #include "xf_input.h" #include "xf_event.h" +#include "xf_input.h" const char* const X11_EVENT_STRINGS[] = { @@ -88,22 +89,24 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app) { int x, y; int w, h; - + x = event->xexpose.x; y = event->xexpose.y; w = event->xexpose.width; h = event->xexpose.height; - + if (!app) { - if (xfc->scale != 1.0) + if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { - xf_draw_screen_scaled(xfc); + xf_draw_screen_scaled(xfc, x - xfc->offset_x, + y - xfc->offset_y, w, h, FALSE); } else { XCopyArea(xfc->display, xfc->primary, - xfc->window->handle, xfc->gc, x, y, w, h, x, y); + xfc->window->handle, xfc->gc, x, y, w, + h, x, y); } } else @@ -111,16 +114,17 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app) xfWindow* xfw; rdpWindow* window; rdpRail* rail = ((rdpContext*) xfc)->rail; - - window = window_list_get_by_extra_id(rail->list, (void*) event->xexpose.window); - - if (window != NULL) + + window = window_list_get_by_extra_id(rail->list, + (void*) event->xexpose.window); + + if (window) { xfw = (xfWindow*) window->extra; xf_UpdateWindowArea(xfc, xfw, x, y, w, h); } } - + return TRUE; } @@ -156,12 +160,12 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window win RootWindowOfScreen(xfc->screen), x, y, &x, &y, &childWindow); } - - if (xfc->scale != 1.0) + + /* Take scaling in to consideration */ + if ( (xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y) ) { - /* Take scaling in to consideration */ - x = (int) (x * (1.0 / xfc->scale)); - y = (int) (y * (1.0 / xfc->scale)); + x = (int)((x - xfc->offset_x) * (1.0 / xfc->settings->ScalingFactor) ); + y = (int)((y - xfc->offset_y) * (1.0 / xfc->settings->ScalingFactor) ); } input->MouseEvent(input, PTR_FLAGS_MOVE, x, y); @@ -176,6 +180,9 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window win static BOOL xf_event_MotionNotify(xfContext* xfc, XEvent* event, BOOL app) { + if (xfc->use_xinput) + return TRUE; + return xf_generic_MotionNotify(xfc, event->xmotion.x, event->xmotion.y, event->xmotion.state, event->xmotion.window, app); } @@ -257,13 +264,16 @@ BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, Window win XTranslateCoordinates(xfc->display, window, RootWindowOfScreen(xfc->screen), x, y, &x, &y, &childWindow); + } - if (xfc->scale != 1.0) + if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) + || (xfc->offset_y)) { - /* Take scaling in to consideration */ - x = (int) (x * (1.0 / xfc->scale)); - y = (int) (y * (1.0 / xfc->scale)); + x = (int) ((x - xfc->offset_x) + * (1.0 / xfc->settings->ScalingFactor)); + y = (int) ((y - xfc->offset_y) + * (1.0 / xfc->settings->ScalingFactor)); } if (extended) @@ -278,6 +288,9 @@ BOOL xf_generic_ButtonPress(xfContext* xfc, int x, int y, int button, Window win static BOOL xf_event_ButtonPress(xfContext* xfc, XEvent* event, BOOL app) { + if (xfc->use_xinput) + return TRUE; + return xf_generic_ButtonPress(xfc, event->xbutton.x, event->xbutton.y, event->xbutton.button, event->xbutton.window, app); } @@ -290,6 +303,7 @@ BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window w rdpInput* input; Window childWindow; + flags = 0; wheel = FALSE; extended = FALSE; @@ -343,11 +357,11 @@ BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window w x, y, &x, &y, &childWindow); } - if (xfc->scale != 1.0) + + if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y)) { - /* Take scaling in to consideration */ - x = (int) (x * (1.0 / xfc->scale)); - y = (int) (y * (1.0 / xfc->scale)); + x = (int) ((x - xfc->offset_x) * (1.0 / xfc->settings->ScalingFactor)); + y = (int) ((y - xfc->offset_y) * (1.0 / xfc->settings->ScalingFactor)); } if (extended) @@ -361,6 +375,9 @@ BOOL xf_generic_ButtonRelease(xfContext* xfc, int x, int y, int button, Window w static BOOL xf_event_ButtonRelease(xfContext* xfc, XEvent* event, BOOL app) { + if (xfc->use_xinput) + return TRUE; + return xf_generic_ButtonRelease(xfc, event->xbutton.x, event->xbutton.y, event->xbutton.button, event->xbutton.window, app); } @@ -542,15 +559,18 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, XEvent* event, BOOL app) rdpWindow* window; rdpRail* rail = ((rdpContext*) xfc)->rail; + +/* This is for resizing the window by dragging the border + if (xfc->width != event->xconfigure.width) { - xfc->scale = (double) event->xconfigure.width / (double) xfc->originalWidth; + xfc->settings->ScalingFactor = (double) event->xconfigure.width / (double) xfc->originalWidth; xfc->currentWidth = event->xconfigure.width; xfc->currentHeight = event->xconfigure.width; xf_draw_screen_scaled(xfc); } - +*/ window = window_list_get_by_extra_id(rail->list, (void*) event->xconfigure.window); if (window != NULL) @@ -568,6 +588,9 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, XEvent* event, BOOL app) RootWindowOfScreen(xfc->screen), 0, 0, &xfw->left, &xfw->top, &childWindow); + + + xfw->width = event->xconfigure.width; xfw->height = event->xconfigure.height; xfw->right = xfw->left + xfw->width - 1; @@ -926,7 +949,6 @@ BOOL xf_event_process(freerdp* instance, XEvent* event) case MotionNotify: status = xf_event_MotionNotify(xfc, event, xfc->remote_app); break; - case ButtonPress: status = xf_event_ButtonPress(xfc, event, xfc->remote_app); break; @@ -1003,6 +1025,7 @@ BOOL xf_event_process(freerdp* instance, XEvent* event) case PropertyNotify: status = xf_event_PropertyNotify(xfc, event, xfc->remote_app); break; + } xf_input_handle_event(xfc, event); diff --git a/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index acdc0da47..158c61778 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -950,10 +950,10 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits XSetClipRectangles(xfc->display, xfc->gc, surface_bits_command->destLeft, surface_bits_command->destTop, - (XRectangle*) message->rects, message->num_rects, YXBanded); + (XRectangle*) message->rects, message->numRects, YXBanded); /* Draw the tiles to primary surface, each is 64x64. */ - for (i = 0; i < message->num_tiles; i++) + for (i = 0; i < message->numTiles; i++) { image = XCreateImage(xfc->display, xfc->visual, 24, ZPixmap, 0, (char*) message->tiles[i]->data, 64, 64, 32, 0); @@ -966,7 +966,7 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits } /* Copy the updated region from backstore to the window. */ - for (i = 0; i < message->num_rects; i++) + for (i = 0; i < message->numRects; i++) { tx = message->rects[i].x + surface_bits_command->destLeft; ty = message->rects[i].y + surface_bits_command->destTop; @@ -988,7 +988,7 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits xfc->bmp_codec_nsc = (BYTE*) realloc(xfc->bmp_codec_nsc, surface_bits_command->width * surface_bits_command->height * 4); - freerdp_image_flip(nsc_context->bmpdata, xfc->bmp_codec_nsc, + freerdp_image_flip(nsc_context->BitmapData, xfc->bmp_codec_nsc, surface_bits_command->width, surface_bits_command->height, 32); image = XCreateImage(xfc->display, xfc->visual, 24, ZPixmap, 0, diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 96fbf974d..b3e296966 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -131,7 +131,7 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, RFX_MESSAGE* msg; xfContext* xfc = (xfContext*) context; - size = width * height * (bpp + 7) / 8; + size = width * height * ((bpp + 7) / 8); if (bitmap->data == NULL) bitmap->data = (BYTE*) malloc(size); @@ -255,7 +255,7 @@ void xf_Pointer_Free(rdpContext* context, rdpPointer* pointer) xf_lock_x11(xfc, FALSE); - if (((xfPointer*) pointer)->cursor != 0) + if (((xfPointer*) pointer)->cursor) XFreeCursor(xfc->display, ((xfPointer*) pointer)->cursor); xf_unlock_x11(xfc, FALSE); @@ -269,10 +269,12 @@ void xf_Pointer_Set(rdpContext* context, rdpPointer* pointer) xf_lock_x11(xfc, FALSE); + xfc->pointer = (xfPointer*) pointer; + /* in RemoteApp mode, window can be null if none has had focus */ - if (xfc->window != NULL) - XDefineCursor(xfc->display, xfc->window->handle, ((xfPointer*) pointer)->cursor); + if (xfc->window) + XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor); xf_unlock_x11(xfc, FALSE); #endif @@ -299,7 +301,9 @@ void xf_Pointer_SetNull(rdpContext* context) nullcursor = XcursorImageLoadCursor(xfc->display, &ci); } - if (xfc->window != NULL && nullcursor != None) + xfc->pointer = NULL; + + if ((xfc->window) && (nullcursor != None)) XDefineCursor(xfc->display, xfc->window->handle, nullcursor); xf_unlock_x11(xfc, FALSE); @@ -313,7 +317,9 @@ void xf_Pointer_SetDefault(rdpContext* context) xf_lock_x11(xfc, FALSE); - if (xfc->window != NULL) + xfc->pointer = NULL; + + if (xfc->window) XUndefineCursor(xfc->display, xfc->window->handle); xf_unlock_x11(xfc, FALSE); diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 4b7309821..7f19d4ba3 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -21,6 +21,13 @@ #include "config.h" #endif +#include +#include + +#ifdef WITH_XCURSOR +#include +#endif + #ifdef WITH_XI #include #endif @@ -28,13 +35,17 @@ #include #include "xf_event.h" - #include "xf_input.h" #ifdef WITH_XI #define MAX_CONTACTS 2 +#define PAN_THRESHOLD 50 +#define ZOOM_THRESHOLD 10 + +#define MIN_FINGER_DIST 5 + typedef struct touch_contact { int id; @@ -43,16 +54,21 @@ typedef struct touch_contact double pos_y; double last_x; double last_y; - + } touchContact; touchContact contacts[MAX_CONTACTS]; int active_contacts; +int lastEvType; XIDeviceEvent lastEvent; double firstDist = -1.0; double lastDist; + double z_vector; +double px_vector; +double py_vector; + int xinput_opcode; int scale_cnt; @@ -68,10 +84,11 @@ const char* xf_input_get_class_string(int class) return "XIScrollClass"; else if (class == XITouchClass) return "XITouchClass"; - + return "XIUnknownClass"; } + int xf_input_init(xfContext* xfc, Window window) { int i, j; @@ -84,87 +101,94 @@ int xf_input_init(xfContext* xfc, Window window) XIEventMask evmasks[64]; int opcode, event, error; BYTE masks[8][XIMaskLen(XI_LASTEVENT)]; - + + z_vector = 0; + px_vector = 0; + py_vector = 0; + nmasks = 0; ndevices = 0; active_contacts = 0; ZeroMemory(contacts, sizeof(touchContact) * MAX_CONTACTS); - + if (!XQueryExtension(xfc->display, "XInputExtension", &opcode, &event, &error)) { printf("XInput extension not available.\n"); return -1; } - + xfc->XInputOpcode = opcode; - + XIQueryVersion(xfc->display, &major, &minor); - + if (major * 1000 + minor < 2002) { printf("Server does not support XI 2.2\n"); return -1; } - + if (xfc->settings->MultiTouchInput) xfc->use_xinput = TRUE; - + info = XIQueryDevice(xfc->display, XIAllDevices, &ndevices); - + for (i = 0; i < ndevices; i++) { BOOL touch = FALSE; XIDeviceInfo* dev = &info[i]; - + for (j = 0; j < dev->num_classes; j++) { XIAnyClassInfo* class = dev->classes[j]; XITouchClassInfo* t = (XITouchClassInfo*) class; - + if ((class->type == XITouchClass) && (t->mode == XIDirectTouch) && - (strcmp(dev->name, "Virtual core pointer") != 0)) + (strcmp(dev->name, "Virtual core pointer") != 0)) { touch = TRUE; } } - + for (j = 0; j < dev->num_classes; j++) { XIAnyClassInfo* class = dev->classes[j]; XITouchClassInfo* t = (XITouchClassInfo*) class; - + if (xfc->settings->MultiTouchInput) { printf("%s (%d) \"%s\" id: %d\n", - xf_input_get_class_string(class->type), - class->type, dev->name, dev->deviceid); + xf_input_get_class_string(class->type), + class->type, dev->name, dev->deviceid); } - + evmasks[nmasks].mask = masks[nmasks]; evmasks[nmasks].mask_len = sizeof(masks[0]); ZeroMemory(masks[nmasks], sizeof(masks[0])); evmasks[nmasks].deviceid = dev->deviceid; - + if ((class->type == XITouchClass) && (t->mode == XIDirectTouch) && - (strcmp(dev->name, "Virtual core pointer") != 0)) + (strcmp(dev->name, "Virtual core pointer") != 0)) { if (xfc->settings->MultiTouchInput) { printf("%s %s touch device (id: %d, mode: %d), supporting %d touches.\n", - dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", - dev->deviceid, t->mode, t->num_touches); + dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", + dev->deviceid, t->mode, t->num_touches); } - + XISetMask(masks[nmasks], XI_TouchBegin); XISetMask(masks[nmasks], XI_TouchUpdate); XISetMask(masks[nmasks], XI_TouchEnd); nmasks++; } - + if (xfc->use_xinput) { - if (!touch && (class->type == XIButtonClass)) + if (!touch && (class->type == XIButtonClass) && strcmp(dev->name, "Virtual core pointer")) { + printf("%s button device (id: %d, mode: %d)\n", + dev->name, + dev->deviceid, t->mode); XISetMask(masks[nmasks], XI_ButtonPress); XISetMask(masks[nmasks], XI_ButtonRelease); XISetMask(masks[nmasks], XI_Motion); @@ -173,51 +197,181 @@ int xf_input_init(xfContext* xfc, Window window) } } } - + if (nmasks > 0) xstatus = XISelectEvents(xfc->display, window, evmasks, nmasks); - + return 0; } -BOOL xf_input_is_duplicate(XIDeviceEvent* event) +BOOL xf_input_is_duplicate(XGenericEventCookie* cookie) { + XIDeviceEvent* event; + + event = cookie->data; + + if ( (lastEvent.time == event->time) && - (lastEvent.detail == event->detail) && - (lastEvent.event_x == event->event_x) && - (lastEvent.event_y == event->event_y) ) + (lastEvType == cookie->evtype) && + (lastEvent.detail == event->detail) && + (lastEvent.event_x == event->event_x) && + (lastEvent.event_y == event->event_y) ) { return TRUE; } - + return FALSE; } -void xf_input_save_last_event(XIDeviceEvent* event) +void xf_input_save_last_event(XGenericEventCookie* cookie) { + XIDeviceEvent* event; + + event = cookie->data; + + lastEvType = cookie->evtype; + lastEvent.time = event->time; lastEvent.detail = event->detail; lastEvent.event_x = event->event_x; lastEvent.event_y = event->event_y; + +} + +void xf_input_detect_pan(xfContext* xfc) +{ + double dx[2]; + double dy[2]; + + double px; + double py; + + double dist_x; + double dist_y; + + if (active_contacts != 2) + { + return; + } + + dx[0] = contacts[0].pos_x - contacts[0].last_x; + dx[1] = contacts[1].pos_x - contacts[1].last_x; + + dy[0] = contacts[0].pos_y - contacts[0].last_y; + dy[1] = contacts[1].pos_y - contacts[1].last_y; + + px = fabs(dx[0]) < fabs(dx[1]) ? dx[0] : dx[1]; + py = fabs(dy[0]) < fabs(dy[1]) ? dy[0] : dy[1]; + + px_vector += px; + py_vector += py; + + dist_x = fabs(contacts[0].pos_x - contacts[1].pos_x); + dist_y = fabs(contacts[0].pos_y - contacts[1].pos_y); + + + //only pan in x if dist_y is greater than something + if(dist_y > MIN_FINGER_DIST) + { + + if(px_vector > PAN_THRESHOLD) + { + + { + PanningChangeEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.XPan = 5; + e.YPan = 0; + PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); + } + + px_vector = 0; + + px_vector = 0; + py_vector = 0; + z_vector = 0; + } + else if(px_vector < -PAN_THRESHOLD) + { + { + PanningChangeEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.XPan = -5; + e.YPan = 0; + PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); + } + + px_vector = 0; + + px_vector = 0; + py_vector = 0; + z_vector = 0; + } + + } + + if(dist_x > MIN_FINGER_DIST) + { + + if(py_vector > PAN_THRESHOLD) + { + { + PanningChangeEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.XPan = 0; + e.YPan = 5; + PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); + } + + py_vector = 0; + + px_vector = 0; + py_vector = 0; + z_vector = 0; + } + else if(py_vector < -PAN_THRESHOLD) + { + { + PanningChangeEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.XPan = 0; + e.YPan = -5; + PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); + } + + py_vector = 0; + + px_vector = 0; + py_vector = 0; + z_vector = 0; + } + } + } void xf_input_detect_pinch(xfContext* xfc) { double dist; double zoom; + double delta; ResizeWindowEventArgs e; - + if (active_contacts != 2) { firstDist = -1.0; return; } - + + /* first calculate the distance */ dist = sqrt(pow(contacts[1].pos_x - contacts[0].last_x, 2.0) + - pow(contacts[1].pos_y - contacts[0].last_y, 2.0)); - + pow(contacts[1].pos_y - contacts[0].last_y, 2.0)); + /* if this is the first 2pt touch */ if (firstDist <= 0) { @@ -225,50 +379,69 @@ void xf_input_detect_pinch(xfContext* xfc) lastDist = firstDist; scale_cnt = 0; z_vector = 0; + + px_vector = 0; + py_vector = 0; + z_vector = 0; } else { delta = lastDist - dist; - + + if(delta > 1.0) + delta = 1.0; + if(delta < -1.0) + delta = -1.0; + /* compare the current distance to the first one */ zoom = (dist / firstDist); - + z_vector += delta; - //printf("d: %.2f\n", delta); - + + lastDist = dist; - - if (z_vector > 10) + + if (z_vector > ZOOM_THRESHOLD) { - xfc->scale -= 0.05; - - if (xfc->scale < 0.5) - xfc->scale = 0.5; - - XResizeWindow(xfc->display, xfc->window->handle, xfc->originalWidth * xfc->scale, xfc->originalHeight * xfc->scale); - + xfc->settings->ScalingFactor -= 0.05; + + if (xfc->settings->ScalingFactor < 0.8) + xfc->settings->ScalingFactor = 0.8; + EventArgsInit(&e, "xfreerdp"); - e.width = (int) xfc->originalWidth * xfc->scale; - e.height = (int) xfc->originalHeight * xfc->scale; + e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; + e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; + + xf_transform_window(xfc); PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); - + xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE); + + z_vector = 0; + + px_vector = 0; + py_vector = 0; z_vector = 0; } - - if (z_vector < -10) + + if (z_vector < -ZOOM_THRESHOLD) { - xfc->scale += 0.05; - - if (xfc->scale > 1.5) - xfc->scale = 1.5; - - XResizeWindow(xfc->display, xfc->window->handle, xfc->originalWidth * xfc->scale, xfc->originalHeight * xfc->scale); - + xfc->settings->ScalingFactor += 0.05; + + if (xfc->settings->ScalingFactor > 1.2) + xfc->settings->ScalingFactor = 1.2; + EventArgsInit(&e, "xfreerdp"); - e.width = (int) xfc->originalWidth * xfc->scale; - e.height = (int) xfc->originalHeight * xfc->scale; + e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; + e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; + + xf_transform_window(xfc); PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); - + xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE); + + z_vector = 0; + + px_vector = 0; + py_vector = 0; z_vector = 0; } } @@ -277,7 +450,9 @@ void xf_input_detect_pinch(xfContext* xfc) void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event) { int i; - + if(active_contacts == MAX_CONTACTS) + printf("Houston, we have a problem!\n\n"); + for (i = 0; i < MAX_CONTACTS; i++) { if (contacts[i].id == 0) @@ -286,7 +461,7 @@ void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event) contacts[i].count = 1; contacts[i].pos_x = event->event_x; contacts[i].pos_y = event->event_y; - + active_contacts++; break; } @@ -296,7 +471,6 @@ void xf_input_touch_begin(xfContext* xfc, XIDeviceEvent* event) void xf_input_touch_update(xfContext* xfc, XIDeviceEvent* event) { int i; - for (i = 0; i < MAX_CONTACTS; i++) { if (contacts[i].id == event->detail) @@ -306,9 +480,10 @@ void xf_input_touch_update(xfContext* xfc, XIDeviceEvent* event) contacts[i].last_y = contacts[i].pos_y; contacts[i].pos_x = event->event_x; contacts[i].pos_y = event->event_y; - + xf_input_detect_pinch(xfc); - + xf_input_detect_pan(xfc); + break; } } @@ -317,7 +492,6 @@ void xf_input_touch_update(xfContext* xfc, XIDeviceEvent* event) void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event) { int i; - for (i = 0; i < MAX_CONTACTS; i++) { if (contacts[i].id == event->detail) @@ -326,7 +500,7 @@ void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event) contacts[i].count = 0; //contacts[i].pos_x = (int)event->event_x; //contacts[i].pos_y = (int)event->event_y; - + active_contacts--; break;printf("TouchBegin\n"); } @@ -336,39 +510,39 @@ void xf_input_touch_end(xfContext* xfc, XIDeviceEvent* event) int xf_input_handle_event_local(xfContext* xfc, XEvent* event) { XGenericEventCookie* cookie = &event->xcookie; - + XGetEventData(xfc->display, cookie); - + if ((cookie->type == GenericEvent) && (cookie->extension == xfc->XInputOpcode)) { switch (cookie->evtype) { case XI_TouchBegin: - if (xf_input_is_duplicate(cookie->data) == FALSE) + if (xf_input_is_duplicate(cookie) == FALSE) xf_input_touch_begin(xfc, cookie->data); - xf_input_save_last_event(cookie->data); + xf_input_save_last_event(cookie); break; - + case XI_TouchUpdate: - if (xf_input_is_duplicate(cookie->data) == FALSE) + if (xf_input_is_duplicate(cookie) == FALSE) xf_input_touch_update(xfc, cookie->data); - xf_input_save_last_event(cookie->data); + xf_input_save_last_event(cookie); break; - + case XI_TouchEnd: - if (xf_input_is_duplicate(cookie->data) == FALSE) + if (xf_input_is_duplicate(cookie) == FALSE) xf_input_touch_end(xfc, cookie->data); - xf_input_save_last_event(cookie->data); + xf_input_save_last_event(cookie); break; - + default: printf("unhandled xi type= %d\n", cookie->evtype); break; } } - + XFreeEventData(xfc->display,cookie); - + return 0; } @@ -384,73 +558,126 @@ char* xf_input_touch_state_string(DWORD flags) return "TouchUnknown"; } +void xf_input_hide_cursor(xfContext* xfc) +{ +#ifdef WITH_XCURSOR + if (!xfc->cursorHidden) + { + XcursorImage ci; + XcursorPixel xp = 0; + static Cursor nullcursor = None; + + xf_lock_x11(xfc, FALSE); + + ZeroMemory(&ci, sizeof(ci)); + ci.version = XCURSOR_IMAGE_VERSION; + ci.size = sizeof(ci); + ci.width = ci.height = 1; + ci.xhot = ci.yhot = 0; + ci.pixels = &xp; + nullcursor = XcursorImageLoadCursor(xfc->display, &ci); + + if ((xfc->window) && (nullcursor != None)) + XDefineCursor(xfc->display, xfc->window->handle, nullcursor); + + xfc->cursorHidden = TRUE; + + xf_unlock_x11(xfc, FALSE); + } +#endif +} + +void xf_input_show_cursor(xfContext* xfc) +{ +#ifdef WITH_XCURSOR + xf_lock_x11(xfc, FALSE); + + if (xfc->cursorHidden) + { + if (xfc->window) + { + if (!xfc->pointer) + XUndefineCursor(xfc->display, xfc->window->handle); + else + XDefineCursor(xfc->display, xfc->window->handle, xfc->pointer->cursor); + } + + xfc->cursorHidden = FALSE; + } + + xf_unlock_x11(xfc, FALSE); +#endif +} + int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtype) { int x, y; int touchId; int contactId; RdpeiClientContext* rdpei = xfc->rdpei; - + if (!rdpei) return 0; + + xf_input_hide_cursor(xfc); touchId = event->detail; x = (int) event->event_x; y = (int) event->event_y; - + if (evtype == XI_TouchBegin) { - //printf("TouchBegin: %d\n", touchId); + printf("TouchBegin: %d\n", touchId); contactId = rdpei->TouchBegin(rdpei, touchId, x, y); } else if (evtype == XI_TouchUpdate) { - //printf("TouchUpdate: %d\n", touchId); + printf("TouchUpdate: %d\n", touchId); contactId = rdpei->TouchUpdate(rdpei, touchId, x, y); } else if (evtype == XI_TouchEnd) { - //printf("TouchEnd: %d\n", touchId); + printf("TouchEnd: %d\n", touchId); contactId = rdpei->TouchEnd(rdpei, touchId, x, y); } - + return 0; } int xf_input_event(xfContext* xfc, XIDeviceEvent* event, int evtype) { - return TRUE; + xf_input_show_cursor(xfc); switch (evtype) { case XI_ButtonPress: - printf("ButtonPress\n"); + xf_generic_ButtonPress(xfc, (int) event->event_x, (int) event->event_y, - event->detail, event->event, xfc->remote_app); + event->detail, event->event, xfc->remote_app); break; - + case XI_ButtonRelease: - printf("ButtonRelease\n"); + xf_generic_ButtonRelease(xfc, (int) event->event_x, (int) event->event_y, - event->detail, event->event, xfc->remote_app); + event->detail, event->event, xfc->remote_app); break; - + case XI_Motion: - printf("Motion\n"); + xf_generic_MotionNotify(xfc, (int) event->event_x, (int) event->event_y, - event->detail, event->event, xfc->remote_app); + event->detail, event->event, xfc->remote_app); break; } - + return 0; } int xf_input_handle_event_remote(xfContext* xfc, XEvent* event) { XGenericEventCookie* cookie = &event->xcookie; - + XGetEventData(xfc->display, cookie); - + if ((cookie->type == GenericEvent) && (cookie->extension == xfc->XInputOpcode)) { switch (cookie->evtype) @@ -458,23 +685,23 @@ int xf_input_handle_event_remote(xfContext* xfc, XEvent* event) case XI_TouchBegin: xf_input_touch_remote(xfc, cookie->data, XI_TouchBegin); break; - + case XI_TouchUpdate: xf_input_touch_remote(xfc, cookie->data, XI_TouchUpdate); break; - + case XI_TouchEnd: xf_input_touch_remote(xfc, cookie->data, XI_TouchEnd); break; - + default: xf_input_event(xfc, cookie->data, cookie->evtype); break; } } - + XFreeEventData(xfc->display,cookie); - + return 0; } @@ -493,10 +720,10 @@ void xf_process_rdpei_event(xfContext* xfc, wMessage* event) { case RdpeiChannel_ServerReady: break; - + case RdpeiChannel_SuspendTouch: break; - + case RdpeiChannel_ResumeTouch: break; } @@ -505,14 +732,16 @@ void xf_process_rdpei_event(xfContext* xfc, wMessage* event) int xf_input_handle_event(xfContext* xfc, XEvent* event) { #ifdef WITH_XI - if (xfc->settings->MultiTouchInput) + //printf("m:%d g:%d\n", (xfc->settings->MultiTouchInput), (xfc->settings->MultiTouchGestures) ); + if (xfc->settings->MultiTouchInput) { return xf_input_handle_event_remote(xfc, event); } - - if (xfc->enableScaling) + + if (xfc->settings->MultiTouchGestures) return xf_input_handle_event_local(xfc, event); + #endif - + return 0; } diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c index 0c85119c8..8b5cf0b33 100644 --- a/client/X11/xf_keyboard.c +++ b/client/X11/xf_keyboard.c @@ -216,7 +216,160 @@ BOOL xf_kbd_handle_special_keys(xfContext* xfc, KeySym keysym) return TRUE; } } - + + if (keysym == XK_period) + { + if ((xf_kbd_key_pressed(xfc, XK_Alt_L) + || xf_kbd_key_pressed(xfc, XK_Alt_R)) + && (xf_kbd_key_pressed(xfc, XK_Control_L) + || xf_kbd_key_pressed(xfc, + XK_Control_R))) + { + //Zoom in (scale larger) + double s = xfc->settings->ScalingFactor; + s += 0.1; + if (s > 2.0) + s = 2.0; + + xfc->settings->ScalingFactor = s; + + xfc->currentWidth = xfc->originalWidth * s; + xfc->currentHeight = xfc->originalHeight * s; + + xf_transform_window(xfc); + + { + ResizeWindowEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; + e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; + PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); + } + xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE); + return TRUE; + } + } + + if (keysym == XK_comma) + { + if ((xf_kbd_key_pressed(xfc, XK_Alt_L) + || xf_kbd_key_pressed(xfc, XK_Alt_R)) + && (xf_kbd_key_pressed(xfc, XK_Control_L) + || xf_kbd_key_pressed(xfc, + XK_Control_R))) + { + //Zoom out (scale smaller) + double s = xfc->settings->ScalingFactor; + s -= 0.1; + if (s < 0.5) + s = 0.5; + + xfc->settings->ScalingFactor = s; + + xfc->currentWidth = xfc->originalWidth * s; + xfc->currentHeight = xfc->originalHeight * s; + + xf_transform_window(xfc); + + { + ResizeWindowEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.width = (int) xfc->originalWidth * xfc->settings->ScalingFactor; + e.height = (int) xfc->originalHeight * xfc->settings->ScalingFactor; + PubSub_OnResizeWindow(((rdpContext*) xfc)->pubSub, xfc, &e); + } + + xf_draw_screen_scaled(xfc, 0, 0, 0, 0, FALSE); + return TRUE; + } + } + + if (keysym == XK_KP_4) + { + if ((xf_kbd_key_pressed(xfc, XK_Alt_L) + || xf_kbd_key_pressed(xfc, XK_Alt_R)) + && (xf_kbd_key_pressed(xfc, XK_Control_L) + || xf_kbd_key_pressed(xfc, + XK_Control_R))) + { + + { + PanningChangeEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.XPan = -5; + e.YPan = 0; + PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); + } + + return TRUE; + } + } + + if (keysym == XK_KP_6) + { + if ((xf_kbd_key_pressed(xfc, XK_Alt_L) + || xf_kbd_key_pressed(xfc, XK_Alt_R)) + && (xf_kbd_key_pressed(xfc, XK_Control_L) + || xf_kbd_key_pressed(xfc, + XK_Control_R))) + { + + { + PanningChangeEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.XPan = 5; + e.YPan = 0; + PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); + } + return TRUE; + } + } + + if (keysym == XK_KP_8) + { + if ((xf_kbd_key_pressed(xfc, XK_Alt_L) + || xf_kbd_key_pressed(xfc, XK_Alt_R)) + && (xf_kbd_key_pressed(xfc, XK_Control_L) + || xf_kbd_key_pressed(xfc, + XK_Control_R))) + { + { + PanningChangeEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.XPan = 0; + e.YPan = -5; + PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); + } + return TRUE; + } + } + + if (keysym == XK_KP_2) + { + if ((xf_kbd_key_pressed(xfc, XK_Alt_L) + || xf_kbd_key_pressed(xfc, XK_Alt_R)) + && (xf_kbd_key_pressed(xfc, XK_Control_L) + || xf_kbd_key_pressed(xfc, + XK_Control_R))) + { + { + PanningChangeEventArgs e; + + EventArgsInit(&e, "xfreerdp"); + e.XPan = 0; + e.YPan = 5; + PubSub_OnPanningChange(((rdpContext*) xfc)->pubSub, xfc, &e); + } + return TRUE; + } + } + + return FALSE; } diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index a24ac7190..e12cdc344 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -44,6 +44,7 @@ #ifdef WITH_XI #include +#include "xf_input.h" #endif #include "xf_input.h" diff --git a/client/X11/xfreerdp-channels.1.xml b/client/X11/xfreerdp-channels.1.xml new file mode 100644 index 000000000..e69de29bb diff --git a/client/X11/xfreerdp-examples.1.xml b/client/X11/xfreerdp-examples.1.xml new file mode 100644 index 000000000..462649f68 --- /dev/null +++ b/client/X11/xfreerdp-examples.1.xml @@ -0,0 +1,89 @@ + + Examples + + + xfreerdp connection.rdp /p:Pwd123! /f + + Connect in fullscreen mode using a stored configuration connection.rdp and the password Pwd123! + + + + xfreerdp /u:CONTOSO\\JohnDoe /p:Pwd123! /v:rdp.contoso.com + + Connect to host rdp.contoso.com with user CONTOSO\\JohnDoe and password Pwd123! + + + + xfreerdp /u:JohnDoe /p:Pwd123! /w:1366 /h:768 /v:192.168.1.100:4489 + + Connect to host 192.168.1.100 on port 4489 with user JohnDoe, password Pwd123!. The screen width is set to 1366 and the height to 768 + + + + xfreerdp /u:JohnDoe /p:Pwd123! /vmconnect:C824F53E-95D2-46C6-9A18-23A5BB403532 /v:192.168. 1.100 + + Establish a connection to host 192.168.1.100 with user JohnDoe, password Pwd123! and connect to Hyper-V console (use port 2179, disable negotiation) with VMID C824F53E-95D2-46C6-9A18-23A5BB403532 + + + + +clipboard + + Activate clipboard redirection + + + + /drive:home,/home/user + + Activate drive redirection of /home/user as home drive + + + + /smartcard:<device> + + Activate smartcard redirection for device device + + + + /printer:<device>,<driver> + + Activate printer redirection for printer device using driver driver + + + + /serial:<device> + + Activate serial port redirection for port device + + + + /parallel:<device> + + Activate parallel port redirection for port device + + + + /sound:sys:alsa + + Activate audio output redirection using device sys:alsa + + + + /microphone:sys:alsa + + Activate audio input redirection using device sys:alsa + + + + /multimedia:sys:alsa + + Activate multimedia redirection using device sys:alsa + + + + /usb:id,dev:054c:0268 + + Activate USB device redirection for the device identified by 054c:0268 + + + + diff --git a/client/X11/xfreerdp.1.xml b/client/X11/xfreerdp.1.xml deleted file mode 100644 index bf7f774e6..000000000 --- a/client/X11/xfreerdp.1.xml +++ /dev/null @@ -1,571 +0,0 @@ - - - - 2011-08-27 - - The FreeRDP Team - - - - xfreerdp - 1 - freerdp - xfreerdp - - - xfreerdp - FreeRDP X11 client - - - - 2011-08-27 - - - xfreerdp [options] server[:port] [[options] server[:port] …] - - - - - 2011-08-27 - - DESCRIPTION - - xfreerdp is an X11 Remote Desktop Protocol (RDP) - client which is part of the FreeRDP project. An RDP server is built-in - to many editions of Windows. Alternative servers included xrdp and VRDP (VirtualBox). - - - - OPTIONS - - - -0 - - - Attach to the admin console of the server. - - - - - -a bpp - - - Sets the color depth for the connection to bpp bits per pixel. - Valid values are 8, 15, 16, 24 and 32. The default value is the color depth of the FreeRDP-window. - - - - - -c dir - - - Sets the working-dir to dir. - This parameter is only used when an AlternateShell () is requested. - dir should contain the executable file specified in the AlternateShell. - - - - - -D - - - Removes the windows decorations. - - - - - -d - - - Domain used in authentication. - - - - - -f - - - start in full screen mode. This mode can always be en- and disabled using Ctrl-Alt-Enter. - - - - - -T text - - - Sets the window title to text. - - - - - -g geometry - - - Sets the size of the FreeRDP window (and of the remote desktop, when establishing a new connection). - geometry can have one of the following forms: - - - - WxH - - in this case the resulting window will be of - WxH pixels. - - - - - P% - - in this case the resulting window will be P% - of your screen. - - - - - The special keyword workarea - - in this case the resulting window will be of the same size as your workarea. - - - - - - - - -h - - - Print help. - - - - - -k id - - - Sets the keyboard-layout-id to id. - - - - - -K - - - Do not interfere with window manager bindings. Normally, xfreerdp captures all keystrokes while its window is focused. - - - - - -n hostname - - - Set the reported client hostname to hostname. - Default is to automatically detect the hostname. - - - - - -o - - - Play audio on the console instead of redirecting to the client. - - - - - -p password - - - Password used in authentication. - - - - - -s shell - - - Sets the startup-shell to shell. - This parameter should contain a complete path to the alternate shell. - If the alternete shell requires a different working directory use . - - - - - -t port - - - Connect to port, instead of the default 3389. - - - - - -u username - - - Username used in authentication. - - - - - -x flag - - - Set the experience performance flags. - flag can be one of: - - - - m - (modem): Equivalent to 15. - - - - - b - (broadband): Equivalent to 1. - - - - - l - (lan): Equivalent to 0. - - - - - num - A hexadecimal number that - represents a bit-mask, were numbers mean the following - Taken from - MS-RDPBCGR Section 2.2.1.11.1.1.1 - Extended Info Packet: - - - 1: Disable desktop wallpaper. - - - 2: Disable full-window drag (only the window outline is displayed when the window is moved). - - - 4: Disable menu animations. - - - 8: Disable user interface themes. - - - 20: Disable mouse cursor shadows. - - - 40: Disable cursor blinking. - - - 80: Enable font smoothing. - - - 100: Enable Desktop Composition. - - - - - - - - - - -X xid - - embed xfreerdp into window with xid. - - - - -z - - - Enable compression. - - - - - --app - - - initialize a RemoteApp connection. This implies -g workarea. - - - - - --no-auth - - - Skips authentication. This is useful e.g. for the current FreeRDP server that doesn't yet support server-side authentication. - - - - - --authonly - - - Only authenticates. This is useful to test your credentials (username and password). - Returns status code 0 if the client can connect, 1 otherwise. Requires a username, - password and connection host at the command line. - - - - - --bcv3 codec - - Use codec for bitmap cache v3 - - - - - --no-bmp-cache - - - Disable bitmap cache. - - - - - --certificate-name name - - - use name for the logon certificate, instead of the server name - - - - - --composition - - - Enable composition (RDVH only, not to be confused with remote composition). - - - - - --ext extname - - - load extension extname - - - - - --no-fastpath - - - Disables fast-path. Use slow-path packets instead, which have larger headers. - It might be good for debugging certain issues when you suspect it might be - linked to the parsing of one of the two header types. - - - - - --from-stdin - - Prompts for unspecified arguments -u username, -p - password, -d domain and connection host. This is useful to - hide arguments from ps. Also useful for scripts that will - feed these arguments to the client via (what else?) stdin. - - - - - --disable-full-window-drag - - - Disable full window drag. - - - - - --gdi backend - - - GDI (Graphics Device Interface) rendering backend. backend can be either sw (software) or hw (hardware). - - - - - --ignore-certificate - - - ignore verification of logon certificate. - - - - - --kbd-list - - - list all keyboard layout ids used by -k - - - - - --disable-menu-animations - - - Disable menu animations. - - - - - --no-motion - - - Don't send mouse motion events. - - - - - --no-nego - - disable negotiation of security layer and enforce highest enabled security protocol. - - - - - --no-nla - - - Disable network level authentication. - - - - - --nsc - - - Enable NSCodec. - - - - - --no-osb - - - Disable off screen bitmaps. - - - - - --pcb blob - - - Use preconnection blob. - - - - - --pcid id - - - Use preconnection id. - - - - - --plugin pluginname - - - load pluginname - - - - - --no-rdp - - - Disable Standard RDP encryption. - - - - - --rfx - - - Enable RemoteFX. - - - - - --rfx-mode - - - RemoteFX operational flags. flags can be either v[ideo], i[mage]), default is video. - - - - - --no-salted-checksum - - - disable salted checksums with Standard RDP encryption. - - - - - --ntlm - - - force NTLM protocol version. version can be one of 1 or 2. - - - - - --sec proto - - - force protocol security. proto can be one of rdp, tls or nla. - - - - - --disable-theming - - - Disable theming. - - - - - --no-tls - - - Disable TLS encryption. - - - - - --tsg -username -password -hostname - - - Use Terminal Server Gateway with -username -password -hostname. - - - - - --version - - - Print version information. - - - - - --disable-wallpaper - - - Disable wallpaper. - - - - - - - LINKS - - http://www.freerdp.com/ - - - diff --git a/client/X11/xfreerdp.1.xml.in b/client/X11/xfreerdp.1.xml.in new file mode 100644 index 000000000..4dbb42083 --- /dev/null +++ b/client/X11/xfreerdp.1.xml.in @@ -0,0 +1,60 @@ + + + + + ] +> + + + + @MAN_TODAY@ + + The FreeRDP Team + + + + xfreerdp + 1 + freerdp + xfreerdp + + + xfreerdp + FreeRDP X11 client + + + + @MAN_TODAY@ + + + xfreerdp [file] [options] [/v:server[:port]] + + + + + @MAN_TODAY@ + + DESCRIPTION + + xfreerdp is an X11 Remote Desktop Protocol (RDP) + client which is part of the FreeRDP project. An RDP server is built-in + to many editions of Windows. Alternative servers included xrdp and VRDP (VirtualBox). + + + + &syntax; + + &channels; + + &examples; + + + LINKS + + http://www.freerdp.com/ + + + diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 37f187487..a7aaa70a2 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -89,6 +89,7 @@ struct xf_context BOOL unobscured; BOOL debug; xfWindow* window; + xfPointer* pointer; xfWorkArea workArea; int current_desktop; BOOL remote_app; @@ -96,6 +97,7 @@ struct xf_context HCLRCONV clrconv; HANDLE mutex; BOOL UseXThreads; + BOOL cursorHidden; HGDI_DC hdc; BYTE* primary_buffer; @@ -106,7 +108,6 @@ struct xf_context UINT16 frame_x2; UINT16 frame_y2; - double scale; int originalWidth; int originalHeight; int currentWidth; @@ -114,6 +115,9 @@ struct xf_context int XInputOpcode; BOOL enableScaling; + int offset_x; + int offset_y; + BOOL focused; BOOL use_xinput; BOOL mouse_active; @@ -208,7 +212,8 @@ enum XF_EXIT_CODE void xf_lock_x11(xfContext* xfc, BOOL display); void xf_unlock_x11(xfContext* xfc, BOOL display); -void xf_draw_screen_scaled(xfContext* xfc); +void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scale); +void xf_transform_window(xfContext* xfc); DWORD xf_exit_code_from_disconnect_reason(DWORD reason); diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index e249cd0db..2b9841e5f 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -25,9 +25,10 @@ set(${MODULE_PREFIX}_SRCS compatibility.h file.c) -set(FREERDP_CHANNELS_CLIENT_PATH "../../channels/client") foreach(FREERDP_CHANNELS_CLIENT_SRC ${FREERDP_CHANNELS_CLIENT_SRCS}) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} "${FREERDP_CHANNELS_CLIENT_PATH}/${FREERDP_CHANNELS_CLIENT_SRC}") + get_filename_component(NINC ${FREERDP_CHANNELS_CLIENT_SRC} PATH) + include_directories(${NINC}) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} "${FREERDP_CHANNELS_CLIENT_SRC}") endforeach() if(MSVC) @@ -53,7 +54,9 @@ target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) set_target_properties(${MODULE_NAME} PROPERTIES LINK_INTERFACE_LIBRARIES "") -install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) +if (NOT WITH_WAYK) + install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Common") diff --git a/client/common/client.c b/client/common/client.c index acc47d064..824b46859 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -56,8 +56,8 @@ rdpContext* freerdp_client_context_new(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) freerdp_context_new(instance); context = instance->context; - context->instance = instance; - context->settings = instance->settings; + context->instance = instance; + context->settings = instance->settings; return context; } @@ -112,16 +112,13 @@ int freerdp_client_parse_command_line(rdpContext* context, int argc, char** argv if (settings->ConnectionFile) { - rdpFile* file = freerdp_client_rdp_file_new(); - freerdp_client_parse_rdp_file(file, settings->ConnectionFile); - freerdp_client_populate_settings_from_rdp_file(file, settings); - freerdp_client_rdp_file_free(file); + return freerdp_client_parse_connection_file(context, settings->ConnectionFile); } return status; } -int freerdp_client_parse_connection_file(rdpContext* context, char* filename) +int freerdp_client_parse_connection_file(rdpContext* context, const char* filename) { rdpFile* file; @@ -136,11 +133,35 @@ int freerdp_client_parse_connection_file(rdpContext* context, char* filename) int freerdp_client_parse_connection_file_buffer(rdpContext* context, BYTE* buffer, size_t size) { rdpFile* file; + int status = -1; file = freerdp_client_rdp_file_new(); - freerdp_client_parse_rdp_file_buffer(file, buffer, size); - freerdp_client_populate_settings_from_rdp_file(file, context->settings); + if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) + && freerdp_client_populate_settings_from_rdp_file(file, context->settings)) + { + status = 0; + } + freerdp_client_rdp_file_free(file); - return 0; + return status; +} + +int freerdp_client_write_connection_file(rdpContext* context, const char* filename, BOOL unicode) +{ + rdpFile* file; + int status = -1; + + file = freerdp_client_rdp_file_new(); + if (freerdp_client_populate_rdp_file_from_settings(file, context->settings)) + { + if (freerdp_client_write_rdp_file(file, filename, unicode)) + { + status = 0; + } + } + + freerdp_client_rdp_file_free(file); + + return status; } diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 06514b59a..ce14ab125 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -90,7 +90,9 @@ COMMAND_LINE_ARGUMENT_A args[] = { "printer", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Redirect printer device" }, { "usb", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect USB device" }, { "multitouch", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect multitouch input" }, + { "gestures", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Consume multitouch input locally" }, { "echo", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "echo", "Echo channel" }, + { "disp", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Display control" }, { "fonts", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Smooth fonts (ClearType)" }, { "aero", COMMAND_LINE_VALUE_BOOL, NULL, NULL, BoolValueFalse, -1, NULL, "Desktop composition" }, { "window-drag", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Full window drag" }, @@ -134,6 +136,8 @@ COMMAND_LINE_ARGUMENT_A args[] = { "wm-class", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "set the WM_CLASS hint for the window instance" }, { "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "print version" }, { "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "?", "print help" }, + { "play-rfx", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Replay rfx pcap file" }, + { "auth-only", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Authenticate only." }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; @@ -595,6 +599,11 @@ int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT p[0] = "rdpei"; freerdp_client_add_dynamic_channel(settings, count, p); } + CommandLineSwitchCase(arg, "gestures") + { + printf("gestures\n"); + settings->MultiTouchGestures = TRUE; + } CommandLineSwitchCase(arg, "echo") { char* p[1]; @@ -605,6 +614,16 @@ int freerdp_client_command_line_post_filter(void* context, COMMAND_LINE_ARGUMENT freerdp_client_add_dynamic_channel(settings, count, p); } + CommandLineSwitchCase(arg, "disp") + { + char* p[1]; + int count; + + count = 1; + p[0] = "disp"; + + freerdp_client_add_dynamic_channel(settings, count, p); + } CommandLineSwitchCase(arg, "sound") { if (arg->Flags & COMMAND_LINE_VALUE_PRESENT) @@ -863,13 +882,10 @@ int freerdp_detect_windows_style_command_line_syntax(int argc, char** argv, int* } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); - if (detect_status == 0) - { - if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST)) - detect_status = -1; - } + if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST)) + detect_status = -1; - return 0; + return detect_status; } int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, int* count) @@ -899,13 +915,10 @@ int freerdp_detect_posix_style_command_line_syntax(int argc, char** argv, int* c } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); - if (detect_status == 0) - { - if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST)) - detect_status = -1; - } + if ((status <= COMMAND_LINE_ERROR) && (status >= COMMAND_LINE_ERROR_LAST)) + detect_status = -1; - return 0; + return detect_status; } BOOL freerdp_client_detect_command_line(int argc, char** argv, DWORD* flags) @@ -1032,6 +1045,7 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin freerdp_client_command_line_pre_filter, freerdp_client_command_line_post_filter); } + arg = CommandLineFindArgumentA(args, "v"); arg = args; @@ -1241,8 +1255,9 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin settings->GatewayHostname = _strdup(settings->ServerHostname); } - settings->GatewayUsageMethod = TRUE; + settings->GatewayUsageMethod = TSC_PROXY_MODE_DIRECT; settings->GatewayUseSameCredentials = TRUE; + settings->GatewayEnabled = TRUE; } CommandLineSwitchCase(arg, "gu") { @@ -1426,6 +1441,7 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin CommandLineSwitchCase(arg, "nsc") { settings->NSCodec = TRUE; + settings->ColorDepth = 32; } CommandLineSwitchCase(arg, "jpeg") { @@ -1597,6 +1613,15 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin { settings->WmClass = _strdup(arg->Value); } + CommandLineSwitchCase(arg, "play-rfx") + { + settings->PlayRemoteFxFile = _strdup(arg->Value); + settings->PlayRemoteFx = TRUE; + } + CommandLineSwitchCase(arg, "auth-only") + { + settings->AuthenticationOnly = arg->Value ? TRUE : FALSE; + } CommandLineSwitchDefault(arg) { @@ -1626,7 +1651,7 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin if (settings->DisableThemes) settings->PerformanceFlags |= PERF_DISABLE_THEMING; - if (settings->GatewayUsageMethod) + if (settings->GatewayEnabled) { if (settings->GatewayUseSameCredentials) { @@ -1655,7 +1680,7 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin FillMemory(arg->Value, strlen(arg->Value), '*'); } - return 1; + return status; } int freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpSettings* settings, char* name, void* data) diff --git a/client/common/compatibility.c b/client/common/compatibility.c index 8f14199b9..788b41354 100644 --- a/client/common/compatibility.c +++ b/client/common/compatibility.c @@ -473,7 +473,9 @@ int freerdp_client_parse_old_command_line_arguments(int argc, char** argv, rdpSe CommandLineSwitchCase(arg, "p") { settings->Password = _strdup(arg->Value); - fprintf(stderr, "-p %s -> /p:%s\n", arg->Value, arg->Value); + fprintf(stderr, "-p ****** -> /p:******\n"); + /* Hide the value from 'ps'. */ + FillMemory(arg->Value, strlen(arg->Value), '*'); } CommandLineSwitchCase(arg, "s") { diff --git a/client/common/file.c b/client/common/file.c index afe40e9b1..a1ec5a362 100644 --- a/client/common/file.c +++ b/client/common/file.c @@ -439,7 +439,7 @@ BOOL freerdp_client_parse_rdp_file_buffer(rdpFile* file, BYTE* buffer, size_t si return freerdp_client_parse_rdp_file_buffer_ascii(file, buffer, size); } -BOOL freerdp_client_parse_rdp_file(rdpFile* file, char* name) +BOOL freerdp_client_parse_rdp_file(rdpFile* file, const char* name) { BYTE* buffer; FILE* fp = NULL; @@ -480,7 +480,8 @@ BOOL freerdp_client_parse_rdp_file(rdpFile* file, char* name) return freerdp_client_parse_rdp_file_buffer(file, buffer, file_size); } -#define SETTING_MODIFIED(_settings, _field) (_settings->settings_modified[FreeRDP_##_field]) +#define WRITE_ALL_SETTINGS FALSE +#define SETTING_MODIFIED(_settings, _field) (WRITE_ALL_SETTINGS || _settings->settings_modified[FreeRDP_##_field]) #define SETTING_MODIFIED_SET(_target, _settings, _field) if SETTING_MODIFIED(_settings, _field) _target = _settings->_field BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, rdpSettings* settings) @@ -529,9 +530,9 @@ BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, rdpSettings* } -BOOL freerdp_client_write_rdp_file(rdpFile* file, char* name, BOOL unicode) +BOOL freerdp_client_write_rdp_file(rdpFile* file, const char* name, BOOL unicode) { - BOOL success = FALSE; + int rc = 0; char* buffer; int len, len2; FILE* fp = NULL; @@ -559,22 +560,22 @@ BOOL freerdp_client_write_rdp_file(rdpFile* file, char* name, BOOL unicode) fwrite(BOM_UTF16_LE, sizeof(BYTE), 2, fp); fwrite(unicodestr, 2, len, fp); - free(unicodestr); + free(unicodestr); } else { fwrite(buffer, 1, len, fp); } - fflush(fp); - fclose(fp); + rc = fflush(fp); + rc = fclose(fp); } } if (buffer != NULL) free(buffer); - return success; + return (rc == 0); } #define WRITE_RDP_FILE_DECLARE(_file, _buffer, _size) \ @@ -604,7 +605,6 @@ if (~__rdpFile->_field) \ #define WRITE_RDP_FILE_VALUE_RETURN \ return __required_size; -// TODO: Optimize by only writing the fields that have a value i.e ~((size_t) file->FieldName) != 0 size_t freerdp_client_write_rdp_file_buffer(rdpFile* file, char* buffer, size_t size) { WRITE_RDP_FILE_DECLARE(file, buffer, size) @@ -731,11 +731,19 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* if (~((size_t) file->GatewayHostname)) freerdp_set_param_string(settings, FreeRDP_GatewayHostname, file->GatewayHostname); + if (~file->GatewayUsageMethod) - freerdp_set_param_bool(settings, FreeRDP_GatewayUsageMethod, file->GatewayUsageMethod); + { + freerdp_set_param_uint32(settings, FreeRDP_GatewayUsageMethod, file->GatewayUsageMethod); + + if (file->GatewayUsageMethod == TSC_PROXY_MODE_DIRECT) + freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE); + else if (file->GatewayUsageMethod == TSC_PROXY_MODE_NONE_DETECT) + freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE); + } + if (~file->PromptCredentialOnce) - freerdp_set_param_bool(settings, FreeRDP_GatewayUsageMethod, file->GatewayUsageMethod); - settings->GatewayUseSameCredentials = TRUE; + freerdp_set_param_bool(settings, FreeRDP_GatewayUseSameCredentials, TRUE); if (~file->RemoteApplicationMode) freerdp_set_param_bool(settings, FreeRDP_RemoteApplicationMode, file->RemoteApplicationMode); diff --git a/client/iOS/Models/RDPSession.m b/client/iOS/Models/RDPSession.m index df924e29f..d61d59a57 100644 --- a/client/iOS/Models/RDPSession.m +++ b/client/iOS/Models/RDPSession.m @@ -175,7 +175,8 @@ NSString* TSXSessionDidFailToConnectNotification = @"TSXSessionDidFailToConnect" settings->GatewayUsername = strdup([_params UTF8StringForKey:@"tsg_username"]); settings->GatewayPassword = strdup([_params UTF8StringForKey:@"tsg_password"]); settings->GatewayDomain = strdup([_params UTF8StringForKey:@"tsg_domain"]); - settings->GatewayUsageMethod = TRUE; + settings->GatewayUsageMethod = TSC_PROXY_MODE_DIRECT; + settings->GatewayEnabled = TRUE; settings->GatewayUseSameCredentials = FALSE; } diff --git a/cmake/AndroidToolchain.cmake b/cmake/AndroidToolchain.cmake index 9216bf55d..9eeb7beaf 100644 --- a/cmake/AndroidToolchain.cmake +++ b/cmake/AndroidToolchain.cmake @@ -1,5 +1,5 @@ # Copyright (c) 2010-2011, Ethan Rublee -# Copyright (c) 2011-2012, Andrey Kamaev +# Copyright (c) 2011-2013, Andrey Kamaev # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -35,7 +35,6 @@ # # The file is mantained by the OpenCV project. The latest version can be get at # http://code.opencv.org/projects/opencv/repository/revisions/master/changes/android/android.toolchain.cmake -# Git commit: 084b1c796900b0825fc4e0593ab3143da3f3a90e # # Usage Linux: # $ export ANDROID_NDK=/absolute/path/to/the/android-ndk @@ -282,8 +281,19 @@ # [+] updated for NDK r8c # [+] added support for clang compiler # - December 2012 +# [+] suppress warning about unused CMAKE_TOOLCHAIN_FILE variable +# [+] adjust API level to closest compatible as NDK does # [~] fixed ccache full path search # [+] updated for NDK r8d +# [~] compiler options are aligned with NDK r8d +# - March 2013 +# [+] updated for NDK r8e (x86 version) +# [+] support x86_64 version of NDK +# - April 2013 +# [+] support non-release NDK layouts (from Linaro git and Android git) +# [~] automatically detect if explicit link to crtbegin_*.o is needed +# - June 2013 +# [~] fixed stl include path for standalone toolchain made by NDK >= r8c # ------------------------------------------------------------------------------ cmake_minimum_required( VERSION 2.6.3 ) @@ -293,6 +303,10 @@ if( DEFINED CMAKE_CROSSCOMPILING ) return() endif() +if( CMAKE_TOOLCHAIN_FILE ) + # touch toolchain variable only to suppress "unused variable" warning +endif() + get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE ) if( _CMAKE_IN_TRY_COMPILE ) include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL ) @@ -312,7 +326,7 @@ endif() # rpath makes low sence for Android set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) -set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) +set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS) if( CMAKE_HOST_WIN32 ) file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) @@ -456,19 +470,32 @@ if( ANDROID_FORBID_SYGWIN ) endif() endif() + # detect current host platform +if( NOT DEFINED ANDROID_NDK_HOST_X64 AND CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64") + set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) + mark_as_advanced( ANDROID_NDK_HOST_X64 ) +endif() + set( TOOL_OS_SUFFIX "" ) if( CMAKE_HOST_APPLE ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" ) elseif( CMAKE_HOST_WIN32 ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "windows" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" ) set( TOOL_OS_SUFFIX ".exe" ) elseif( CMAKE_HOST_UNIX ) - set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" ) else() message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) endif() +if( NOT ANDROID_NDK_HOST_X64 ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) +endif() + # see if we have path to Android NDK __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) if( NOT ANDROID_NDK ) @@ -500,35 +527,19 @@ if( NOT ANDROID_NDK ) endif( ANDROID_NDK ) endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) endif( NOT ANDROID_NDK ) + # remember found paths if( ANDROID_NDK ) get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) - # try to detect change - if( CMAKE_AR ) - string( LENGTH "${ANDROID_NDK}" __length ) - string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) - if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK ) - message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. - " ) - endif() - unset( __androidNdkPreviousPath ) - unset( __length ) - endif() set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE ) set( BUILD_WITH_ANDROID_NDK True ) - file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_TXT LIMIT_COUNT 1 REGEX r[0-9]+[a-z]? ) - - if(${ANDROID_NDK_RELEASE_TXT} MATCHES "^r[0-9]+[a-z] \([^ ]+\)$") - string( REGEX REPLACE "^(r[0-9]+[a-z]) \(([^ ]+)\)$" "\\1" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_TXT}" ) - string( REGEX REPLACE "^(r[0-9]+[a-z]) \(([^ ]+)\)$" "\\2" ANDROID_NDK_RELEASE_EXTRA "${ANDROID_NDK_RELEASE_TXT}" ) - - set( ANDROID_NDK_64BIT True) - set( ANDROID_NDK_HOST_SYSTEM_NAME "${ANDROID_NDK_HOST_SYSTEM_NAME}_64" ) - + if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" ) + file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX r[0-9]+[a-z]? ) + string( REGEX MATCH r[0-9]+[a-z]? ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" ) else() - set( ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_TXT}" ) + set( ANDROID_NDK_RELEASE "r1x" ) + set( ANDROID_NDK_RELEASE_FULL "unreleased" ) endif() - elseif( ANDROID_STANDALONE_TOOLCHAIN ) get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) # try to detect change @@ -555,6 +566,51 @@ else() sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) endif() +# android NDK layout +if( BUILD_WITH_ANDROID_NDK ) + if( NOT DEFINED ANDROID_NDK_LAYOUT ) + # try to automatically detect the layout + if( EXISTS "${ANDROID_NDK}/RELEASE.TXT") + set( ANDROID_NDK_LAYOUT "RELEASE" ) + elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" ) + set( ANDROID_NDK_LAYOUT "LINARO" ) + elseif( EXISTS "${ANDROID_NDK}/../../gcc/" ) + set( ANDROID_NDK_LAYOUT "ANDROID" ) + endif() + endif() + set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" ) + mark_as_advanced( ANDROID_NDK_LAYOUT ) + if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment + set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) + elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment + set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) + else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE" + set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" ) + endif() + get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE ) + + # try to detect change of NDK + if( CMAKE_AR ) + string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length ) + string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) + if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH ) + message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. + " ) + endif() + unset( __androidNdkPreviousPath ) + unset( __length ) + endif() +endif() + + # get all the details about standalone toolchain if( BUILD_WITH_STANDALONE_TOOLCHAIN ) __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) @@ -582,22 +638,27 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) endif() endif() -macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar ) - foreach( __toolchain ${${__availableToolchainsVar}} ) - if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK}/toolchains/${__toolchain}/prebuilt/" ) +macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) + foreach( __toolchain ${${__availableToolchainsLst}} ) + if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) else() set( __gcc_toolchain "${__toolchain}" ) endif() - __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK}/toolchains/${__gcc_toolchain}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) + __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) if( __machine ) - string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?$" __version "${__gcc_toolchain}" ) - string( REGEX MATCH "^[^-]+" __arch "${__gcc_toolchain}" ) + string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) + if( __machine MATCHES i686 ) + set( __arch "x86" ) + elseif( __machine MATCHES arm ) + set( __arch "arm" ) + elseif( __machine MATCHES mipsel ) + set( __arch "mipsel" ) + endif() list( APPEND __availableToolchainMachines "${__machine}" ) list( APPEND __availableToolchainArchs "${__arch}" ) list( APPEND __availableToolchainCompilerVersions "${__version}" ) - else() - list( REMOVE_ITEM ${__availableToolchainsVar} "${__toolchain}" ) + list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) endif() unset( __gcc_toolchain ) endforeach() @@ -611,19 +672,31 @@ if( BUILD_WITH_ANDROID_NDK ) set( __availableToolchainMachines "" ) set( __availableToolchainArchs "" ) set( __availableToolchainCompilerVersions "" ) - if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK}/toolchains/${ANDROID_TOOLCHAIN_NAME}/" ) + if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" ) # do not go through all toolchains if we know the name - set( __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains ) + set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) + if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) + if( __availableToolchains ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) + endif() + endif() endif() if( NOT __availableToolchains ) - file( GLOB __availableToolchains RELATIVE "${ANDROID_NDK}/toolchains" "${ANDROID_NDK}/toolchains/*" ) + file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" ) if( __availableToolchains ) - list(SORT __availableToolchains) # we need clang to go after gcc + list(SORT __availableToolchainsLst) # we need clang to go after gcc + endif() + __LIST_FILTER( __availableToolchainsLst "^[.]" ) + __LIST_FILTER( __availableToolchainsLst "llvm" ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) + if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) + if( __availableToolchains ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) + endif() endif() - __LIST_FILTER( __availableToolchains "^[.]" ) - __LIST_FILTER( __availableToolchains "llvm" ) - __GLOB_NDK_TOOLCHAINS( __availableToolchains ) endif() if( NOT __availableToolchains ) message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." ) @@ -636,11 +709,11 @@ set( __uniqToolchainArchNames ${__availableToolchainArchs} ) list( REMOVE_DUPLICATES __uniqToolchainArchNames ) list( SORT __uniqToolchainArchNames ) foreach( __arch ${__uniqToolchainArchNames} ) -list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) + list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) endforeach() unset( __uniqToolchainArchNames ) if( NOT ANDROID_SUPPORTED_ABIS ) -message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) + message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) endif() # choose target ABI @@ -752,6 +825,7 @@ else() list( GET __availableToolchainArchs ${__idx} __toolchainArch ) if( __toolchainArch STREQUAL ANDROID_ARCH_FULLNAME ) list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion ) + string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}") if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion ) set( __toolchainMaxVersion "${__toolchainVersion}" ) set( __toolchainIdx ${__idx} ) @@ -779,11 +853,22 @@ unset( __availableToolchainCompilerVersions ) # choose native API level __INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) string( REGEX MATCH "[0-9]+" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) -# TODO: filter out unsupported levels +# adjust API level +set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} ) +foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) + if( NOT __level GREATER ANDROID_NATIVE_API_LEVEL AND NOT __level LESS __real_api_level ) + set( __real_api_level ${__level} ) + endif() +endforeach() +if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL EQUAL __real_api_level ) + message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'") + set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} ) +endif() +unset(__real_api_level) # validate list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) if( __levelIdx EQUAL -1 ) - message( SEND_ERROR "Specified Android native API level (${ANDROID_NATIVE_API_LEVEL}) is not supported by your NDK/toolchain." ) + message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." ) else() if( BUILD_WITH_ANDROID_NDK ) __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" ) @@ -893,7 +978,11 @@ if( BUILD_WITH_STANDALONE_TOOLCHAIN ) set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) if( NOT ANDROID_STL STREQUAL "none" ) - set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) + if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) + # old location ( pre r8c ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) + endif() if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) @@ -944,11 +1033,11 @@ if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" ) elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" ) string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}") string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-4.6" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) - if( NOT EXISTS "${ANDROID_NDK}/toolchains/llvm-${ANDROID_CLANG_VERSION}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}/bin/clang${TOOL_OS_SUFFIX}" ) - message( FATAL_ERROR "Could not find the " ) + if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" ) + message( FATAL_ERROR "Could not find the Clang compiler driver" ) endif() set( ANDROID_COMPILER_IS_CLANG 1 ) - set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK}/toolchains/llvm-${ANDROID_CLANG_VERSION}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) + set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) else() set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) unset( ANDROID_COMPILER_IS_CLANG CACHE ) @@ -962,7 +1051,7 @@ endif() # setup paths and STL for NDK if( BUILD_WITH_ANDROID_NDK ) - set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK}/toolchains/${ANDROID_GCC_TOOLCHAIN_NAME}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) + set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" ) if( ANDROID_STL STREQUAL "none" ) @@ -1021,11 +1110,11 @@ if( BUILD_WITH_ANDROID_NDK ) endif() # find libsupc++.a - rtti & exceptions if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" ) - if( ANDROID_NDK_RELEASE STRGREATER "r8" ) # r8b - set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) - elseif( NOT ANDROID_NDK_RELEASE STRLESS "r7" AND ANDROID_NDK_RELEASE STRLESS "r8b") - set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) - else( ANDROID_NDK_RELEASE STRLESS "r7" ) + set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer + if( NOT EXISTS "${__libsupcxx}" ) + set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8 + endif() + if( NOT EXISTS "${__libsupcxx}" ) # before r7 if( ARMEABI_V7A ) if( ANDROID_FORCE_ARM_BUILD ) set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" ) @@ -1075,7 +1164,7 @@ unset( _ndk_ccache ) # setup the cross-compiler if( NOT CMAKE_C_COMPILER ) - if( NDK_CCACHE ) + if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" ) set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" ) if( ANDROID_COMPILER_IS_CLANG ) @@ -1147,11 +1236,25 @@ set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm ) remove_definitions( -DANDROID ) add_definitions( -DANDROID ) -if(ANDROID_SYSROOT MATCHES "[ ;\"]") - set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) +if( ANDROID_SYSROOT MATCHES "[ ;\"]" ) + if( CMAKE_HOST_WIN32 ) + # try to convert path to 8.3 form + file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" ) + execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}" + OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE __result ERROR_QUIET ) + if( __result EQUAL 0 ) + file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT ) + set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) + else() + set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) + endif() + else() + set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" ) + endif() if( NOT _CMAKE_IN_TRY_COMPILE ) - # quotes will break try_compile and compiler identification - message(WARNING "Your Android system root has non-alphanumeric symbols. It can break compiler features detection and the whole build.") + # quotes can break try_compile and compiler identification + message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n") endif() else() set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) @@ -1159,38 +1262,52 @@ endif() # NDK flags if( ARMEABI OR ARMEABI_V7A ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__" ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -funwind-tables" ) if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) - # It is recommended to use the -mthumb compiler flag to force the generation - # of 16-bit Thumb-1 instructions (the default being 32-bit ARM ones). - set( ANDROID_CXX_FLAGS_RELEASE "-mthumb" ) - set( ANDROID_CXX_FLAGS_DEBUG "-marm -finline-limit=64" ) + set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" ) + endif() else() # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI - # O3 instead of O2/Os in release mode - like cmake sets for desktop gcc - set( ANDROID_CXX_FLAGS_RELEASE "-marm" ) - set( ANDROID_CXX_FLAGS_DEBUG "-marm -finline-limit=300" ) + set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) + endif() endif() elseif( X86 ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) - set( ANDROID_CXX_FLAGS_RELEASE "" ) - set( ANDROID_CXX_FLAGS_DEBUG "-finline-limit=300" ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) + else() + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fPIC" ) + endif() + set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) elseif( MIPS ) - set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -funwind-tables -fmessage-length=0 -fno-inline-functions-called-once -frename-registers" ) - set( ANDROID_CXX_FLAGS_RELEASE "-finline-limit=300 -fno-strict-aliasing" ) - set( ANDROID_CXX_FLAGS_DEBUG "-finline-functions -fgcse-after-reload -frerun-cse-after-loop" ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0" ) + set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) + set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" ) + set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) + endif() elseif() set( ANDROID_CXX_FLAGS_RELEASE "" ) set( ANDROID_CXX_FLAGS_DEBUG "" ) endif() -if( NOT X86 ) - set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) +set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries + +if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) endif() -set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries -set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -fomit-frame-pointer" ) -set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} -fno-strict-aliasing -fno-omit-frame-pointer" ) +if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/ +endif() # ABI-specific flags if( ARMEABI_V7A ) @@ -1208,22 +1325,18 @@ elseif( ARMEABI ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) endif() +if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) + set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) + set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) + set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) +else() + set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) + set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) + set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) +endif() + # STL if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) - if( ANDROID_STL MATCHES "gnustl" ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) - else() - set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) - set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) - set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) - endif() - if ( X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" ) - # workaround "undefined reference to `__dso_handle'" problem - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) - endif() if( EXISTS "${__libstl}" ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" ) @@ -1242,9 +1355,12 @@ if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) endif() if( ANDROID_STL MATCHES "gnustl" ) - set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} -lm" ) - set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} -lm" ) - set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -lm" ) + if( NOT EXISTS "${ANDROID_LIBM_PATH}" ) + set( ANDROID_LIBM_PATH -lm ) + endif() + set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" ) + set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" ) + set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" ) endif() endif() @@ -1280,7 +1396,14 @@ if( ARMEABI_V7A ) endif() if( ANDROID_NO_UNDEFINED ) - set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) + if( MIPS ) + # there is some sysroot-related problem in mips linker... + if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) + endif() + else() + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) + endif() endif() if( ANDROID_SO_UNDEFINED ) @@ -1327,9 +1450,6 @@ if( ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} ${ANDROID_CXX_FLAGS}" ) endif() if( BUILD_WITH_ANDROID_NDK ) - if(ANDROID_ARCH_NAME STREQUAL "arm" ) - set( ANDROID_CXX_FLAGS "-isystem ${ANDROID_CLANG_TOOLCHAIN_ROOT}/lib/clang/${ANDROID_CLANG_VERSION}/include ${ANDROID_CXX_FLAGS}" ) - endif() set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" ) endif() endif() @@ -1345,6 +1465,12 @@ set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared li set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" ) set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" ) +# put flags to cache (for debug purpose only) +set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" ) +set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" ) +set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) +set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) + # finish flags set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) @@ -1357,9 +1483,9 @@ set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FL set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" ) - set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK}/toolchains/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) - set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK}/toolchains/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) - set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK}/toolchains/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) + set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) + set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) + set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) endif() # configure rtti @@ -1386,6 +1512,43 @@ endif() include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) link_directories( "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ) +# detect if need link crtbegin_so.o explicitly +if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) + set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" ) + string( REPLACE "" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" ) + string( REPLACE "" "-shared" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" ) + string( REPLACE "" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + separate_arguments( __cmd ) + foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN ) + if( ${__var} ) + set( __tmp "${${__var}}" ) + separate_arguments( __tmp ) + string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}") + endif() + endforeach() + string( REPLACE "'" "" __cmd "${__cmd}" ) + string( REPLACE "\"" "" __cmd "${__cmd}" ) + execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET ) + if( __cmd_result EQUAL 0 ) + set( ANDROID_EXPLICIT_CRT_LINK ON ) + else() + set( ANDROID_EXPLICIT_CRT_LINK OFF ) + endif() +endif() + +if( ANDROID_EXPLICIT_CRT_LINK ) + set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) + set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) +endif() + # setup output directories set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" ) set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) @@ -1475,7 +1638,9 @@ endmacro() if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) set( __toolchain_config "") foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN ANDROID_SET_OBSOLETE_VARIABLES + ANDROID_NDK_HOST_X64 ANDROID_NDK + ANDROID_NDK_LAYOUT ANDROID_STANDALONE_TOOLCHAIN ANDROID_TOOLCHAIN_NAME ANDROID_ABI @@ -1489,6 +1654,8 @@ if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO + ANDROID_LIBM_PATH + ANDROID_EXPLICIT_CRT_LINK ) if( DEFINED ${__var} ) if( "${__var}" MATCHES " ") @@ -1531,6 +1698,8 @@ endif() # ANDROID_NDK # ANDROID_STANDALONE_TOOLCHAIN # ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain +# ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems) +# ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID) # LIBRARY_OUTPUT_PATH_ROOT : # NDK_CCACHE : # Obsolete: @@ -1553,7 +1722,7 @@ endif() # BUILD_ANDROID : always TRUE # BUILD_WITH_ANDROID_NDK : TRUE if NDK is used # BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used -# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86", "linux-x86_64" or "darwin-x86" depending on host platform +# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform # ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86" or "mips" depending on ANDROID_ABI # ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e; set only for NDK # ANDROID_ARCH_NAME : "arm" or "x86" or "mips" depending on ANDROID_ABI @@ -1576,6 +1745,7 @@ endif() # ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime # ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used # ANDROID_CLANG_VERSION : version of clang compiler if clang is used +# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product//obj/lib/libm.so) to workaround unresolved `sincos` # # Defaults: # ANDROID_DEFAULT_NDK_API_LEVEL diff --git a/cmake/FindDBus.cmake b/cmake/FindDBus.cmake new file mode 100644 index 000000000..b002a754b --- /dev/null +++ b/cmake/FindDBus.cmake @@ -0,0 +1,73 @@ +# - Try to find the low-level D-Bus library +# Once done this will define +# +# DBUS_FOUND - system has D-Bus +# DBUS_INCLUDE_DIR - the D-Bus include directory +# DBUS_ARCH_INCLUDE_DIR - the D-Bus architecture-specific include directory +# DBUS_LIBRARIES - the libraries needed to use D-Bus + +# Copyright (c) 2008, Kevin Kofler, +# modeled after FindLibArt.cmake: +# Copyright (c) 2006, Alexander Neundorf, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + # in cache already + SET(DBUS_FOUND TRUE) + +else (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + IF (NOT WIN32) + FIND_PACKAGE(PkgConfig) + IF (PKG_CONFIG_FOUND) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + pkg_check_modules(_DBUS_PC QUIET dbus-1) + ENDIF (PKG_CONFIG_FOUND) + ENDIF (NOT WIN32) + + FIND_PATH(DBUS_INCLUDE_DIR dbus/dbus.h + ${_DBUS_PC_INCLUDE_DIRS} + /usr/include + /usr/include/dbus-1.0 + /usr/local/include + ) + + FIND_PATH(DBUS_ARCH_INCLUDE_DIR dbus/dbus-arch-deps.h + ${_DBUS_PC_INCLUDE_DIRS} + /usr/lib${LIB_SUFFIX}/include + /usr/lib${LIB_SUFFIX}/dbus-1.0/include + /usr/lib64/include + /usr/lib64/dbus-1.0/include + /usr/lib/include + /usr/lib/dbus-1.0/include + ) + + FIND_LIBRARY(DBUS_LIBRARIES NAMES dbus-1 dbus + PATHS + ${_DBUS_PC_LIBDIR} + ) + + + if (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + set(DBUS_FOUND TRUE) + endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + + + if (DBUS_FOUND) + if (NOT DBus_FIND_QUIETLY) + message(STATUS "Found D-Bus: ${DBUS_LIBRARIES}") + endif (NOT DBus_FIND_QUIETLY) + else (DBUS_FOUND) + if (DBus_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find D-Bus") + endif (DBus_FIND_REQUIRED) + endif (DBUS_FOUND) + + MARK_AS_ADVANCED(DBUS_INCLUDE_DIR DBUS_ARCH_INCLUDE_DIR DBUS_LIBRARIES) + +endif (DBUS_INCLUDE_DIR AND DBUS_ARCH_INCLUDE_DIR AND DBUS_LIBRARIES) + diff --git a/cmake/FindDbusGlib.cmake b/cmake/FindDbusGlib.cmake new file mode 100644 index 000000000..ae966bc65 --- /dev/null +++ b/cmake/FindDbusGlib.cmake @@ -0,0 +1,38 @@ +# DbusGlib library detection +# +# Copyright 2013 Thinstuff Technologies GmbH +# Copyright 2013 Armin Novak +# +# 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. + +find_package(PkgConfig) +pkg_check_modules(PC_DBUS_GLIB QUIET dbus-glib-1) +set(DBUS_GLIB_DEFINITIONS ${PC_DBUS_GLIB_CFLAGS_OTHER}) + +find_path(DBUS_GLIB_INCLUDE_DIR dbus/dbus-glib.h + HINTS ${PC_DBUS_GLIB_INCLUDEDIR} ${PC_DBUS_GLIB_INCLUDE_DIRS} + PATH_SUFFIXES dbus-glib-1 ) + +find_library(DBUS_GLIB_LIBRARY NAMES dbus-glib-1 dbus-glib + HINTS ${PC_DBUS_GLIB_LIBDIR} ${PC_DBUS_GLIB_LIBRARY_DIRS} ) + +set(DBUS_GLIB_LIBRARIES ${DBUS_GLIB_LIBRARY} ) +set(DBUS_GLIB_INCLUDE_DIRS ${DBUS_GLIB_INCLUDE_DIR} ) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set DBUS_GLIB_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(dbus-glib DEFAULT_MSG + DBUS_GLIB_LIBRARY DBUS_GLIB_INCLUDE_DIR) + +mark_as_advanced(DBUS_GLIB_INCLUDE_DIR DBUS_GLIB_LIBRARY ) diff --git a/cmake/FindDocBookXSL.cmake b/cmake/FindDocBookXSL.cmake new file mode 100644 index 000000000..9192ef9b3 --- /dev/null +++ b/cmake/FindDocBookXSL.cmake @@ -0,0 +1,52 @@ +# Try to find DocBook XSL stylesheet +# Once done, it will define: +# +# DOCBOOKXSL_FOUND - system has the required DocBook XML DTDs +# DOCBOOKXSL_DIR - the directory containing the stylesheets +# used to process DocBook XML + +# Copyright (c) 2010, Luigi Toscano, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +set (STYLESHEET_PATH_LIST + share/xml/docbook/stylesheet/docbook-xsl + share/xml/docbook/xsl-stylesheets + share/sgml/docbook/xsl-stylesheets + share/xml/docbook/stylesheet/nwalsh/current + share/xml/docbook/stylesheet/nwalsh + share/xsl/docbook + share/xsl/docbook-xsl +) + +find_path (DOCBOOKXSL_DIR lib/lib.xsl + PATHS ${CMAKE_SYSTEM_PREFIX_PATH} + PATH_SUFFIXES ${STYLESHEET_PATH_LIST} +) + +if (NOT DOCBOOKXSL_DIR) + # hacks for systems that put the version in the stylesheet dirs + set (STYLESHEET_PATH_LIST) + foreach (STYLESHEET_PREFIX_ITER ${CMAKE_SYSTEM_PREFIX_PATH}) + file(GLOB STYLESHEET_SUFFIX_ITER RELATIVE ${STYLESHEET_PREFIX_ITER} + ${STYLESHEET_PREFIX_ITER}/share/xml/docbook/xsl-stylesheets-* + ) + if (STYLESHEET_SUFFIX_ITER) + list (APPEND STYLESHEET_PATH_LIST ${STYLESHEET_SUFFIX_ITER}) + endif () + endforeach () + + find_path (DOCBOOKXSL_DIR VERSION + PATHS ${CMAKE_SYSTEM_PREFIX_PATH} + PATH_SUFFIXES ${STYLESHEET_PATH_LIST} + ) +endif (NOT DOCBOOKXSL_DIR) + + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args (DocBookXSL + "Could NOT find DocBook XSL stylesheets" + DOCBOOKXSL_DIR) + +mark_as_advanced (DOCBOOKXSL_DIR) diff --git a/cmake/FindImageMagick.cmake b/cmake/FindImageMagick.cmake new file mode 100644 index 000000000..4e8e6d598 --- /dev/null +++ b/cmake/FindImageMagick.cmake @@ -0,0 +1,237 @@ +# - Find the ImageMagick binary suite. +# This module will search for a set of ImageMagick tools specified +# as components in the FIND_PACKAGE call. Typical components include, +# but are not limited to (future versions of ImageMagick might have +# additional components not listed here): +# +# animate +# compare +# composite +# conjure +# convert +# display +# identify +# import +# mogrify +# montage +# stream +# +# If no component is specified in the FIND_PACKAGE call, then it only +# searches for the ImageMagick executable directory. This code defines +# the following variables: +# +# ImageMagick_FOUND - TRUE if all components are found. +# ImageMagick_EXECUTABLE_DIR - Full path to executables directory. +# ImageMagick__FOUND - TRUE if is found. +# ImageMagick__EXECUTABLE - Full path to executable. +# ImageMagick_VERSION_STRING - the version of ImageMagick found +# (since CMake 2.8.8) +# +# ImageMagick_VERSION_STRING will not work for old versions like 5.2.3. +# +# There are also components for the following ImageMagick APIs: +# +# Magick++ +# MagickWand +# MagickCore +# +# For these components the following variables are set: +# +# ImageMagick_FOUND - TRUE if all components are found. +# ImageMagick_INCLUDE_DIRS - Full paths to all include dirs. +# ImageMagick_LIBRARIES - Full paths to all libraries. +# ImageMagick__FOUND - TRUE if is found. +# ImageMagick__INCLUDE_DIRS - Full path to include dirs. +# ImageMagick__LIBRARIES - Full path to libraries. +# +# Example Usages: +# find_package(ImageMagick) +# find_package(ImageMagick COMPONENTS convert) +# find_package(ImageMagick COMPONENTS convert mogrify display) +# find_package(ImageMagick COMPONENTS Magick++) +# find_package(ImageMagick COMPONENTS Magick++ convert) +# +# Note that the standard FIND_PACKAGE features are supported +# (i.e., QUIET, REQUIRED, etc.). + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# Copyright 2007-2008 Miguel A. Figueroa-Villanueva +# Copyright 2012 Rolf Eike Beer +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +#--------------------------------------------------------------------- +# Helper functions +#--------------------------------------------------------------------- +function(FIND_IMAGEMAGICK_API component header) + set(ImageMagick_${component}_FOUND FALSE PARENT_SCOPE) + + find_path(ImageMagick_${component}_INCLUDE_DIR + NAMES ${header} + PATHS + ${ImageMagick_INCLUDE_DIRS} + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ImageMagick\\Current;BinPath]/include" + PATH_SUFFIXES + ImageMagick + DOC "Path to the ImageMagick include dir." + ) + find_library(ImageMagick_${component}_LIBRARY + NAMES ${ARGN} + PATHS + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ImageMagick\\Current;BinPath]/lib" + DOC "Path to the ImageMagick Magick++ library." + ) + + if(ImageMagick_${component}_INCLUDE_DIR AND ImageMagick_${component}_LIBRARY) + set(ImageMagick_${component}_FOUND TRUE PARENT_SCOPE) + + list(APPEND ImageMagick_INCLUDE_DIRS + ${ImageMagick_${component}_INCLUDE_DIR} + ) + list(REMOVE_DUPLICATES ImageMagick_INCLUDE_DIRS) + set(ImageMagick_INCLUDE_DIRS ${ImageMagick_INCLUDE_DIRS} PARENT_SCOPE) + + list(APPEND ImageMagick_LIBRARIES + ${ImageMagick_${component}_LIBRARY} + ) + set(ImageMagick_LIBRARIES ${ImageMagick_LIBRARIES} PARENT_SCOPE) + endif() +endfunction() + +function(FIND_IMAGEMAGICK_EXE component) + set(_IMAGEMAGICK_EXECUTABLE + ${ImageMagick_EXECUTABLE_DIR}/${component}${CMAKE_EXECUTABLE_SUFFIX}) + if(EXISTS ${_IMAGEMAGICK_EXECUTABLE}) + set(ImageMagick_${component}_EXECUTABLE + ${_IMAGEMAGICK_EXECUTABLE} + PARENT_SCOPE + ) + set(ImageMagick_${component}_FOUND TRUE PARENT_SCOPE) + else() + set(ImageMagick_${component}_FOUND FALSE PARENT_SCOPE) + endif() +endfunction() + +#--------------------------------------------------------------------- +# Start Actual Work +#--------------------------------------------------------------------- +# Try to find a ImageMagick installation binary path. +find_path(ImageMagick_EXECUTABLE_DIR + NAMES mogrify${CMAKE_EXECUTABLE_SUFFIX} + PATHS + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\ImageMagick\\Current;BinPath]" + DOC "Path to the ImageMagick binary directory." + NO_DEFAULT_PATH + ) +find_path(ImageMagick_EXECUTABLE_DIR + NAMES mogrify${CMAKE_EXECUTABLE_SUFFIX} + ) + +# Find each component. Search for all tools in same dir +# ; otherwise they should be found +# independently and not in a cohesive module such as this one. +unset(ImageMagick_REQUIRED_VARS) +unset(ImageMagick_DEFAULT_EXECUTABLES) +foreach(component ${ImageMagick_FIND_COMPONENTS} + # DEPRECATED: forced components for backward compatibility + convert mogrify import montage composite + ) + if(component STREQUAL "Magick++") + FIND_IMAGEMAGICK_API(Magick++ Magick++.h + Magick++ CORE_RL_Magick++_ Magick++-Q16 Magick++-Q8 + ) + list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_Magick++_LIBRARY) + elseif(component STREQUAL "MagickWand") + FIND_IMAGEMAGICK_API(MagickWand wand/MagickWand.h + Wand MagickWand CORE_RL_wand_ MagickWand-Q16 MagickWand-Q8 + ) + list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_MagickWand_LIBRARY) + elseif(component STREQUAL "MagickCore") + FIND_IMAGEMAGICK_API(MagickCore magick/MagickCore.h + Magick MagickCore CORE_RL_magick_ MagickCore-6 MagickCore-Q16 MagickCore-Q8 + ) + list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_MagickCore_LIBRARY) + else() + if(ImageMagick_EXECUTABLE_DIR) + FIND_IMAGEMAGICK_EXE(${component}) + endif() + + if(ImageMagick_FIND_COMPONENTS) + list(FIND ImageMagick_FIND_COMPONENTS ${component} is_requested) + if(is_requested GREATER -1) + list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_${component}_EXECUTABLE) + endif() + elseif(ImageMagick_${component}_EXECUTABLE) + # if no components were requested explicitly put all (default) executables + # in the list + list(APPEND ImageMagick_DEFAULT_EXECUTABLES ImageMagick_${component}_EXECUTABLE) + endif() + endif() +endforeach() + +if(NOT ImageMagick_FIND_COMPONENTS AND NOT ImageMagick_DEFAULT_EXECUTABLES) + # No components were requested, and none of the default components were + # found. Just insert mogrify into the list of the default components to + # find so FPHSA below has something to check + list(APPEND ImageMagick_REQUIRED_VARS ImageMagick_mogrify_EXECUTABLE) +elseif(ImageMagick_DEFAULT_EXECUTABLES) + list(APPEND ImageMagick_REQUIRED_VARS ${ImageMagick_DEFAULT_EXECUTABLES}) +endif() + +set(ImageMagick_INCLUDE_DIRS ${ImageMagick_INCLUDE_DIRS}) +set(ImageMagick_LIBRARIES ${ImageMagick_LIBRARIES}) + +if(ImageMagick_mogrify_EXECUTABLE) + execute_process(COMMAND ${ImageMagick_mogrify_EXECUTABLE} -version + OUTPUT_VARIABLE imagemagick_version + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(imagemagick_version MATCHES "^Version: ImageMagick [0-9]") + string(REGEX REPLACE "^Version: ImageMagick ([-0-9\\.]+).*" "\\1" ImageMagick_VERSION_STRING "${imagemagick_version}") + endif() + unset(imagemagick_version) +endif() + +#--------------------------------------------------------------------- +# Standard Package Output +#--------------------------------------------------------------------- +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(ImageMagick + REQUIRED_VARS ${ImageMagick_REQUIRED_VARS} + VERSION_VAR ImageMagick_VERSION_STRING + ) +# Maintain consistency with all other variables. +set(ImageMagick_FOUND ${IMAGEMAGICK_FOUND}) + +#--------------------------------------------------------------------- +# DEPRECATED: Setting variables for backward compatibility. +#--------------------------------------------------------------------- +set(IMAGEMAGICK_BINARY_PATH ${ImageMagick_EXECUTABLE_DIR} + CACHE PATH "Path to the ImageMagick binary directory.") +set(IMAGEMAGICK_CONVERT_EXECUTABLE ${ImageMagick_convert_EXECUTABLE} + CACHE FILEPATH "Path to ImageMagick's convert executable.") +set(IMAGEMAGICK_MOGRIFY_EXECUTABLE ${ImageMagick_mogrify_EXECUTABLE} + CACHE FILEPATH "Path to ImageMagick's mogrify executable.") +set(IMAGEMAGICK_IMPORT_EXECUTABLE ${ImageMagick_import_EXECUTABLE} + CACHE FILEPATH "Path to ImageMagick's import executable.") +set(IMAGEMAGICK_MONTAGE_EXECUTABLE ${ImageMagick_montage_EXECUTABLE} + CACHE FILEPATH "Path to ImageMagick's montage executable.") +set(IMAGEMAGICK_COMPOSITE_EXECUTABLE ${ImageMagick_composite_EXECUTABLE} + CACHE FILEPATH "Path to ImageMagick's composite executable.") +mark_as_advanced( + IMAGEMAGICK_BINARY_PATH + IMAGEMAGICK_CONVERT_EXECUTABLE + IMAGEMAGICK_MOGRIFY_EXECUTABLE + IMAGEMAGICK_IMPORT_EXECUTABLE + IMAGEMAGICK_MONTAGE_EXECUTABLE + IMAGEMAGICK_COMPOSITE_EXECUTABLE + ) \ No newline at end of file diff --git a/cmake/FindPixman.cmake b/cmake/FindPixman.cmake new file mode 100644 index 000000000..7bfca77bd --- /dev/null +++ b/cmake/FindPixman.cmake @@ -0,0 +1,40 @@ +# - Find Pixman +# Find the Pixman libraries +# +# This module defines the following variables: +# PIXMAN_FOUND - true if PIXMAN_INCLUDE_DIR & PIXMAN_LIBRARY are found +# PIXMAN_LIBRARIES - Set when PIXMAN_LIBRARY is found +# PIXMAN_INCLUDE_DIRS - Set when PIXMAN_INCLUDE_DIR is found +# +# PIXMAN_INCLUDE_DIR - where to find pixman.h, etc. +# PIXMAN_LIBRARY - the Pixman library +# + +#============================================================================= +# Copyright 2013 Marc-Andre Moreau +# +# 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. +#============================================================================= + +find_path(PIXMAN_INCLUDE_DIR NAMES pixman.h PATH_SUFFIXES pixman-1) + +find_library(PIXMAN_LIBRARY NAMES pixman-1) + +find_package_handle_standard_args(pixman-1 DEFAULT_MSG PIXMAN_LIBRARY PIXMAN_INCLUDE_DIR) + +if(PIXMAN-1_FOUND) + set(PIXMAN_LIBRARIES ${PIXMAN_LIBRARY}) + set(PIXMAN_INCLUDE_DIRS ${PIXMAN_INCLUDE_DIR}) +endif() + +mark_as_advanced(PIXMAN_INCLUDE_DIR PIXMAN_LIBRARY) diff --git a/cmake/FindUDev.cmake b/cmake/FindUDev.cmake new file mode 100644 index 000000000..f16761572 --- /dev/null +++ b/cmake/FindUDev.cmake @@ -0,0 +1,53 @@ +# razor-de: Configure libudev environment +# +# UDEV_FOUND - system has a libudev +# UDEV_INCLUDE_DIR - where to find header files +# UDEV_LIBRARIES - the libraries to link against udev +# UDEV_STABLE - it's true when is the version greater or equals to 143 - version when the libudev was stabilized in its API +# +# copyright (c) 2011 Petr Vanek +# Redistribution and use is allowed according to the terms of the BSD license. +# + +FIND_PATH( + UDEV_INCLUDE_DIR + libudev.h + /usr/include + /usr/local/include + ${UDEV_PATH_INCLUDES} +) + +FIND_LIBRARY( + UDEV_LIBRARIES + NAMES udev libudev + PATHS + /usr/lib${LIB_SUFFIX} + /usr/local/lib${LIB_SUFFIX} + ${UDEV_PATH_LIB} +) + +IF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) + SET(UDEV_FOUND "YES") + execute_process(COMMAND pkg-config --atleast-version=143 libudev RESULT_VARIABLE UDEV_STABLE) + # retvale is 0 of the condition is "true" so we need to negate the value... + if (UDEV_STABLE) +set(UDEV_STABLE 0) + else (UDEV_STABLE) +set(UDEV_STABLE 1) + endif (UDEV_STABLE) + message(STATUS "libudev stable: ${UDEV_STABLE}") +ENDIF (UDEV_LIBRARIES AND UDEV_INCLUDE_DIR) + +IF (UDEV_FOUND) + MESSAGE(STATUS "Found UDev: ${UDEV_LIBRARIES}") + MESSAGE(STATUS " include: ${UDEV_INCLUDE_DIR}") +ELSE (UDEV_FOUND) + MESSAGE(STATUS "UDev not found.") + MESSAGE(STATUS "UDev: You can specify includes: -DUDEV_PATH_INCLUDES=/opt/udev/include") + MESSAGE(STATUS " currently found includes: ${UDEV_INCLUDE_DIR}") + MESSAGE(STATUS "UDev: You can specify libs: -DUDEV_PATH_LIB=/opt/udev/lib") + MESSAGE(STATUS " currently found libs: ${UDEV_LIBRARIES}") + IF (UDev_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find UDev library") + ENDIF (UDev_FIND_REQUIRED) +ENDIF (UDEV_FOUND) diff --git a/cmake/FindUUID.cmake b/cmake/FindUUID.cmake new file mode 100644 index 000000000..330e5caba --- /dev/null +++ b/cmake/FindUUID.cmake @@ -0,0 +1,113 @@ +# - Try to find UUID +# Once done this will define +# +# UUID_FOUND - system has UUID +# UUID_INCLUDE_DIRS - the UUID include directory +# UUID_LIBRARIES - Link these to use UUID +# UUID_DEFINITIONS - Compiler switches required for using UUID +# +# Copyright (c) 2006 Andreas Schneider +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +if (UUID_LIBRARIES AND UUID_INCLUDE_DIRS) +# in cache already +set(UUID_FOUND TRUE) +else (UUID_LIBRARIES AND UUID_INCLUDE_DIRS) +find_path(UUID_INCLUDE_DIR +NAMES +uuid/uuid.h +PATHS +${UUID_DIR}/include +$ENV{UUID_DIR}/include +$ENV{UUID_DIR} +${DELTA3D_EXT_DIR}/inc +$ENV{DELTA_ROOT}/ext/inc +$ENV{DELTA_ROOT} +~/Library/Frameworks +/Library/Frameworks +/usr/local/include +/usr/include +/usr/include/gdal +/sw/include # Fink +/opt/local/include # DarwinPorts +/opt/csw/include # Blastwave +/opt/include +[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include +/usr/freeware/include + +) + +find_library(UUID_LIBRARY +NAMES +uuid +PATHS +${UUID_DIR}/lib +$ENV{UUID_DIR}/lib +$ENV{UUID_DIR} +${DELTA3D_EXT_DIR}/lib +$ENV{DELTA_ROOT}/ext/lib +$ENV{DELTA_ROOT} +$ENV{OSG_ROOT}/lib +~/Library/Frameworks +/Library/Frameworks +/usr/local/lib +/usr/lib +/sw/lib +/opt/local/lib +/opt/csw/lib +/opt/lib +/usr/freeware/lib64 +) + +find_library(UUID_LIBRARY_DEBUG +NAMES +uuidd +PATHS +${UUID_DIR}/lib +$ENV{UUID_DIR}/lib +$ENV{UUID_DIR} +${DELTA3D_EXT_DIR}/lib +$ENV{DELTA_ROOT}/ext/lib +$ENV{DELTA_ROOT} +$ENV{OSG_ROOT}/lib +~/Library/Frameworks +/Library/Frameworks +/usr/local/lib +/usr/lib +/sw/lib +/opt/local/lib +/opt/csw/lib +/opt/lib +/usr/freeware/lib64 +) + +set(UUID_INCLUDE_DIRS +${UUID_INCLUDE_DIR} +) +set(UUID_LIBRARIES +${UUID_LIBRARY} +) + +if (UUID_INCLUDE_DIRS AND UUID_LIBRARIES) +set(UUID_FOUND TRUE) +endif (UUID_INCLUDE_DIRS AND UUID_LIBRARIES) + +if (UUID_FOUND) +if (NOT UUID_FIND_QUIETLY) +message(STATUS "Found UUID: ${UUID_LIBRARIES}") +endif (NOT UUID_FIND_QUIETLY) +else (UUID_FOUND) +if (UUID_FIND_REQUIRED) +message(FATAL_ERROR "Could not find UUID") +endif (UUID_FIND_REQUIRED) +endif (UUID_FOUND) + +# show the UUID_INCLUDE_DIRS and UUID_LIBRARIES variables only in the advanced view +mark_as_advanced(UUID_INCLUDE_DIRS UUID_LIBRARIES) + +endif (UUID_LIBRARIES AND UUID_INCLUDE_DIRS) diff --git a/cmake/FindXi.cmake b/cmake/FindXi.cmake index d01f4002b..cdd352d82 100644 --- a/cmake/FindXi.cmake +++ b/cmake/FindXi.cmake @@ -14,6 +14,7 @@ # Copyright 2011 O.S. Systems Software Ltda. # Copyright 2011 Otavio Salvador # Copyright 2011 Marc-Andre Moreau +# Copyright 2013 Corey Clayton # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/cmake/FindXrender.cmake b/cmake/FindXrender.cmake index 461217578..efcf72595 100644 --- a/cmake/FindXrender.cmake +++ b/cmake/FindXrender.cmake @@ -1,13 +1,13 @@ -# - Find Xrender -# Find the Xrender libraries +# - Find XRender +# Find the XRender libraries # # This module defines the following variables: -# Xrender_FOUND - true if Xrender_INCLUDE_DIR & Xrender_LIBRARY are found -# Xrender_LIBRARIES - Set when Xrender_LIBRARY is found -# Xrender_INCLUDE_DIRS - Set when Xrender_INCLUDE_DIR is found +# XRENDER_FOUND - true if XRENDER_INCLUDE_DIR & XRENDER_LIBRARY are found +# XRENDER_LIBRARIES - Set when Xrender_LIBRARY is found +# XRENDER_INCLUDE_DIRS - Set when Xrender_INCLUDE_DIR is found # -# Xrender_INCLUDE_DIR - where to find Xrendernput2.h, etc. -# Xrender_LIBRARY - the Xrender library +# XRENDER_INCLUDE_DIR - where to find Xrender.h, etc. +# XRENDER_LIBRARY - the Xrender library # #============================================================================= @@ -36,9 +36,10 @@ include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Xrender DEFAULT_MSG XRENDER_LIBRARY XRENDER_INCLUDE_DIR) if(XRENDER_FOUND) + set(XRENDER_LIBRARIES ${XRENDER_LIBRARY}) set(XRENDER_INCLUDE_DIRS ${XRENDER_INCLUDE_DIR}) + endif() -mark_as_advanced(XRENDER_INCLUDE_DIRS XRENDER_LIBRARIES) - +mark_as_advanced(XRENDER_INCLUDE_DIR XRENDER_LIBRARY) diff --git a/cmake/Findlibusb-1.0.cmake b/cmake/Findlibusb-1.0.cmake new file mode 100644 index 000000000..0163bd521 --- /dev/null +++ b/cmake/Findlibusb-1.0.cmake @@ -0,0 +1,98 @@ +# - Try to find libusb-1.0 +# Once done this will define +# +# LIBUSB_1_FOUND - system has libusb +# LIBUSB_1_INCLUDE_DIRS - the libusb include directory +# LIBUSB_1_LIBRARIES - Link these to use libusb +# LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb +# +# Adapted from cmake-modules Google Code project +# +# Copyright (c) 2006 Andreas Schneider +# +# (Changes for libusb) Copyright (c) 2008 Kyle Machulis +# +# Redistribution and use is allowed according to the terms of the New BSD license. +# +# CMake-Modules Project New BSD License +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of the CMake-Modules Project nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + + +if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) + # in cache already + set(LIBUSB_FOUND TRUE) +else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) + find_path(LIBUSB_1_INCLUDE_DIR + NAMES +libusb.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include +PATH_SUFFIXES +libusb-1.0 + ) + + find_library(LIBUSB_1_LIBRARY + NAMES + usb-1.0 usb + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) + + set(LIBUSB_1_INCLUDE_DIRS + ${LIBUSB_1_INCLUDE_DIR} + ) + set(LIBUSB_1_LIBRARIES + ${LIBUSB_1_LIBRARY} +) + + if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) + set(LIBUSB_1_FOUND TRUE) + endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) + + if (LIBUSB_1_FOUND) + if (NOT libusb_1_FIND_QUIETLY) + message(STATUS "Found libusb-1.0:") +message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") +message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") + endif (NOT libusb_1_FIND_QUIETLY) + else (LIBUSB_1_FOUND) + if (libusb_1_FIND_REQUIRED) + message(FATAL_ERROR "Could not find libusb") + endif (libusb_1_FIND_REQUIRED) + endif (LIBUSB_1_FOUND) + + # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view + mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) + +endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) diff --git a/cmake/MSVCRuntime.cmake b/cmake/MSVCRuntime.cmake index c71a750a5..1c59932c3 100644 --- a/cmake/MSVCRuntime.cmake +++ b/cmake/MSVCRuntime.cmake @@ -5,17 +5,20 @@ macro(configure_msvc_runtime) if("${MSVC_RUNTIME}" STREQUAL "") set(MSVC_RUNTIME "dynamic") endif() + # Set compiler options. set(variables + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELEASE - CMAKE_CXX_FLAGS_RELWITHDEBINFO - ) + CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if(${MSVC_RUNTIME} STREQUAL "static") message(STATUS "MSVC: using statically-linked runtime (/MT and /MTd).") foreach(variable ${variables}) @@ -31,6 +34,25 @@ macro(configure_msvc_runtime) endif() endforeach() endif() + + foreach(variable ${variables}) + if(${variable} MATCHES "/Ob0") + string(REGEX REPLACE "/Ob0" "/Ob2" ${variable} "${${variable}}") + endif() + endforeach() + + foreach(variable ${variables}) + if(${variable} MATCHES "/W3") + string(REGEX REPLACE "/W3" "/W2" ${variable} "${${variable}}") + endif() + endforeach() + + set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") + foreach(variable ${variables}) set(${variable} "${${variable}}" CACHE STRING "MSVC_${variable}" FORCE) endforeach() diff --git a/cmake/MergeStaticLibs.cmake b/cmake/MergeStaticLibs.cmake new file mode 100644 index 000000000..a0673fa7e --- /dev/null +++ b/cmake/MergeStaticLibs.cmake @@ -0,0 +1,130 @@ + +# Copyright (C) 2012 Modelon AB + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the BSD style license. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# FMILIB_License.txt file for more details. + +# You should have received a copy of the FMILIB_License.txt file +# along with this program. If not, contact Modelon AB . + +# Merge_static_libs(outlib lib1 lib2 ... libn) merges a number of static +# libs into a single static library +function(merge_static_libs outlib) + set(libs ${ARGV}) + list(REMOVE_AT libs 0) +# Create a dummy file that the target will depend on + set(dummyfile ${CMAKE_CURRENT_BINARY_DIR}/${outlib}_dummy.c) + file(WRITE ${dummyfile} "const char * dummy = \"${dummyfile}\";") + + add_library(${outlib} STATIC ${dummyfile}) + + if("${CMAKE_CFG_INTDIR}" STREQUAL ".") + set(multiconfig FALSE) + else() + set(multiconfig TRUE) + endif() + +# First get the file names of the libraries to be merged + foreach(lib ${libs}) + get_target_property(libtype ${lib} TYPE) + if(NOT libtype STREQUAL "STATIC_LIBRARY") + message(FATAL_ERROR "Merge_static_libs can only process static libraries") + endif() + if(multiconfig) + foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) + get_target_property("libfile_${CONFIG_TYPE}" ${lib} "LOCATION_${CONFIG_TYPE}") + list(APPEND libfiles_${CONFIG_TYPE} ${libfile_${CONFIG_TYPE}}) + endforeach() + else() + get_target_property(libfile ${lib} LOCATION) + list(APPEND libfiles "${libfile}") + endif(multiconfig) + endforeach() + #message(STATUS "will be merging ${libfiles}") +# Just to be sure: cleanup from duplicates + if(multiconfig) + foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) + list(REMOVE_DUPLICATES libfiles_${CONFIG_TYPE}) + set(libfiles ${libfiles} ${libfiles_${CONFIG_TYPE}}) + endforeach() + endif() + list(REMOVE_DUPLICATES libfiles) + +# Now the easy part for MSVC and for MAC + if(MSVC) + # lib.exe does the merging of libraries just need to conver the list into string + foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) + set(flags "") + foreach(lib ${libfiles_${CONFIG_TYPE}}) + set(flags "${flags} ${lib}") + endforeach() + string(TOUPPER "STATIC_LIBRARY_FLAGS_${CONFIG_TYPE}" PROPNAME) + set_target_properties(${outlib} PROPERTIES ${PROPNAME} "${flags}") + endforeach() + + elseif(APPLE) + # Use OSX's libtool to merge archives + if(multiconfig) + message(FATAL_ERROR "Multiple configurations are not supported") + endif() + get_target_property(outfile ${outlib} LOCATION) + add_custom_command(TARGET ${outlib} POST_BUILD + COMMAND rm ${outfile} + COMMAND /usr/bin/libtool -static -o ${outfile} + ${libfiles} + ) + else() + # general UNIX - need to "ar -x" and then "ar -ru" + if(multiconfig) + message(FATAL_ERROR "Multiple configurations are not supported") + endif() + get_target_property(outfile ${outlib} LOCATION) + message(STATUS "outfile location is ${outfile}") + foreach(lib ${libfiles}) +# objlistfile will contain the list of object files for the library + set(objlistfile ${lib}.objlist) + set(objdir ${lib}.objdir) + set(objlistcmake ${objlistfile}.cmake) +# we only need to extract files once + if(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/cmake.check_cache IS_NEWER_THAN ${objlistcmake}) +#--------------------------------- + FILE(WRITE ${objlistcmake} +"# Extract object files from the library +message(STATUS \"Extracting object files from ${lib}\") +EXECUTE_PROCESS(COMMAND ${CMAKE_AR} -x ${lib} + WORKING_DIRECTORY ${objdir}) +# save the list of object files +EXECUTE_PROCESS(COMMAND ls . + OUTPUT_FILE ${objlistfile} + WORKING_DIRECTORY ${objdir})") +#--------------------------------- + file(MAKE_DIRECTORY ${objdir}) + add_custom_command( + OUTPUT ${objlistfile} + COMMAND ${CMAKE_COMMAND} -P ${objlistcmake} + DEPENDS ${lib}) + endif() + list(APPEND extrafiles "${objlistfile}") + # relative path is needed by ar under MSYS + file(RELATIVE_PATH objlistfilerpath ${objdir} ${objlistfile}) + add_custom_command(TARGET ${outlib} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Running: ${CMAKE_AR} ru ${outfile} @${objlistfilerpath}" + COMMAND ${CMAKE_AR} ru "${outfile}" @"${objlistfilerpath}" + WORKING_DIRECTORY ${objdir}) + endforeach() + add_custom_command(TARGET ${outlib} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "Running: ${CMAKE_RANLIB} ${outfile}" + COMMAND ${CMAKE_RANLIB} ${outfile}) + endif() + file(WRITE ${dummyfile}.base "const char* ${outlib}_sublibs=\"${libs}\";") + add_custom_command( + OUTPUT ${dummyfile} + COMMAND ${CMAKE_COMMAND} -E copy ${dummyfile}.base ${dummyfile} + DEPENDS ${libs} ${extrafiles}) + +endfunction() diff --git a/cmake/today.cmake b/cmake/today.cmake new file mode 100644 index 000000000..51d0031a8 --- /dev/null +++ b/cmake/today.cmake @@ -0,0 +1,16 @@ +# This script returns the current date in ISO format +# +# YYYY-MM-DD +# +MACRO (TODAY RESULT) + IF (WIN32) + EXECUTE_PROCESS(COMMAND "cmd" " /C date +%Y-%m-%d" OUTPUT_VARIABLE ${RESULT}) + string(REGEX REPLACE "(..)/(..)/..(..).*" "\\1/\\2/\\3" ${RESULT} ${${RESULT}}) + ELSEIF(UNIX) + EXECUTE_PROCESS(COMMAND "date" "+%Y-%m-%d" OUTPUT_VARIABLE ${RESULT}) + string(REGEX REPLACE "(..)/(..)/..(..).*" "\\1/\\2/\\3" ${RESULT} ${${RESULT}}) + ELSE (WIN32) + MESSAGE(SEND_ERROR "date not implemented") + SET(${RESULT} 000000) + ENDIF (WIN32) +ENDMACRO (TODAY) diff --git a/config.h.in b/config.h.in index 63de66d8d..83b0abecb 100755 --- a/config.h.in +++ b/config.h.in @@ -30,6 +30,7 @@ #cmakedefine HAVE_SYS_SELECT_H #cmakedefine HAVE_SYS_STRTIO_H #cmakedefine HAVE_EVENTFD_H +#cmakedefine HAVE_TIMERFD_H #cmakedefine HAVE_TM_GMTOFF diff --git a/cunit/test_rfx.c b/cunit/test_rfx.c index aae5b2472..153c7cc64 100644 --- a/cunit/test_rfx.c +++ b/cunit/test_rfx.c @@ -404,7 +404,7 @@ void test_message(void) message = rfx_process_message(context, s->pointer, s->capacity); if (i == 0) { - for (j = 0; j < message->num_tiles; j++) + for (j = 0; j < message->numTiles; j++) { dump_ppm_image(message->tiles[j]->data); } diff --git a/docs/README.android b/docs/README.android index 44a4dbd67..e83af9107 100644 --- a/docs/README.android +++ b/docs/README.android @@ -34,8 +34,8 @@ However, any other static build should work as well. To build openssl: -git clone git@github.com:bmiklautz/Android-external-openssl-ndk-static.git -cd Android-external-openssl-ndk-static +git clone git@github.com:bmiklautz/android-external-openssl-ndk-static.git +cd android-external-openssl-ndk-static ndk-build # found in the Android NDK diff --git a/docs/README.directfb b/docs/README.directfb new file mode 100644 index 000000000..db72c0e85 --- /dev/null +++ b/docs/README.directfb @@ -0,0 +1,3 @@ +The dfreerdp FreeRDP client is currently orphaned and unmaintained so please don't expect it to build and work without problems. + +If you are interested to update and maintain the dfreerdp client please let us know. diff --git a/include/freerdp/channels/rdpdr.h b/include/freerdp/channels/rdpdr.h index 4aa209481..88b1bbe79 100644 --- a/include/freerdp/channels/rdpdr.h +++ b/include/freerdp/channels/rdpdr.h @@ -138,17 +138,7 @@ enum FILE_CREATE_OPTION #define FILE_WRITE_ATTRIBUTES 0x00000100 #endif -#define DELETE 0x00010000 -#define READ_CONTROL 0x00020000 -#define WRITE_DAC 0x00040000 -#define WRITE_OWNER 0x00080000 -#define SYNCHRONIZE 0x00100000 -#define ACCESS_SYSTEM_SECURITY 0x01000000 -#define MAXIMUM_ALLOWED 0x02000000 -#define GENERIC_ALL 0x10000000 -#define GENERIC_EXECUTE 0x20000000 -#define GENERIC_WRITE 0x40000000 -#define GENERIC_READ 0x80000000 +#include #endif diff --git a/include/freerdp/client.h b/include/freerdp/client.h index 67d7a5ebf..ddca7169c 100644 --- a/include/freerdp/client.h +++ b/include/freerdp/client.h @@ -84,8 +84,9 @@ FREERDP_API freerdp* freerdp_client_get_instance(rdpContext* context); FREERDP_API HANDLE freerdp_client_get_thread(rdpContext* context); FREERDP_API int freerdp_client_parse_command_line(rdpContext* context, int argc, char** argv); -FREERDP_API int freerdp_client_parse_connection_file(rdpContext* context, char* filename); +FREERDP_API int freerdp_client_parse_connection_file(rdpContext* context, const char* filename); FREERDP_API int freerdp_client_parse_connection_file_buffer(rdpContext* context, BYTE* buffer, size_t size); +FREERDP_API int freerdp_client_write_connection_file(rdpContext* context, const char* filename, BOOL unicode); #ifdef __cplusplus } diff --git a/include/freerdp/client/disp.h b/include/freerdp/client/disp.h new file mode 100644 index 000000000..fa747db52 --- /dev/null +++ b/include/freerdp/client/disp.h @@ -0,0 +1,64 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Display Update Virtual Channel Extension + * + * Copyright 2013 Marc-Andre Moreau + * + * 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. + */ + +#ifndef FREERDP_CHANNEL_CLIENT_DISP_H +#define FREERDP_CHANNEL_CLIENT_DISP_H + +#define ORIENTATION_LANDSCAPE 0 +#define ORIENTATION_PORTRAIT 90 +#define ORIENTATION_LANDSCAPE_FLIPPED 180 +#define ORIENTATION_PORTRAIT_FLIPPED 270 + +#define DISPLAY_CONTROL_MONITOR_PRIMARY 0x00000001 + +struct _DISPLAY_CONTROL_MONITOR_LAYOUT +{ + UINT32 Flags; + INT32 Left; + INT32 Top; + UINT32 Width; + UINT32 Height; + UINT32 PhysicalWidth; + UINT32 PhysicalHeight; + UINT32 Orientation; + UINT32 DesktopScaleFactor; + UINT32 DeviceScaleFactor; +}; +typedef struct _DISPLAY_CONTROL_MONITOR_LAYOUT DISPLAY_CONTROL_MONITOR_LAYOUT; + +/** + * Client Interface + */ + +#define DISP_DVC_CHANNEL_NAME "Microsoft::Windows::RDS::DisplayControl" + +typedef struct _disp_client_context DispClientContext; + +typedef int (*pcDispSendMonitorLayout)(DispClientContext* context, UINT32 NumMonitors, DISPLAY_CONTROL_MONITOR_LAYOUT* Monitors); + +struct _disp_client_context +{ + void* handle; + void* custom; + + pcDispSendMonitorLayout SendMonitorLayout; +}; + +#endif /* FREERDP_CHANNEL_CLIENT_DISP_H */ + diff --git a/include/freerdp/client/file.h b/include/freerdp/client/file.h index e83aa5ced..8fffdfbe8 100644 --- a/include/freerdp/client/file.h +++ b/include/freerdp/client/file.h @@ -137,12 +137,12 @@ typedef struct rdp_file rdpFile; extern "C" { #endif -FREERDP_API BOOL freerdp_client_parse_rdp_file(rdpFile* file, char* name); +FREERDP_API BOOL freerdp_client_parse_rdp_file(rdpFile* file, const char* name); FREERDP_API BOOL freerdp_client_parse_rdp_file_buffer(rdpFile* file, BYTE* buffer, size_t size); FREERDP_API BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* settings); FREERDP_API BOOL freerdp_client_populate_rdp_file_from_settings(rdpFile* file, rdpSettings* settings); -FREERDP_API BOOL freerdp_client_write_rdp_file(rdpFile* file, char* name, BOOL unicode); +FREERDP_API BOOL freerdp_client_write_rdp_file(rdpFile* file, const char* name, BOOL unicode); FREERDP_API size_t freerdp_client_write_rdp_file_buffer(rdpFile* file, char* buffer, size_t size); FREERDP_API rdpFile* freerdp_client_rdp_file_new(void); diff --git a/include/freerdp/codec/bitmap.h b/include/freerdp/codec/bitmap.h index a0a2e4c82..c652a921b 100644 --- a/include/freerdp/codec/bitmap.h +++ b/include/freerdp/codec/bitmap.h @@ -23,6 +23,12 @@ #include #include +#include +#include + FREERDP_API BOOL bitmap_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size, int srcBpp, int dstBpp); +FREERDP_API int freerdp_bitmap_compress(char* in_data, int width, int height, + wStream* s, int bpp, int byte_limit, int start_line, wStream* temp_s, int e); + #endif /* FREERDP_CODEC_BITMAP_H */ diff --git a/include/freerdp/codec/nsc.h b/include/freerdp/codec/nsc.h index 16fc580f1..9601fb8c2 100644 --- a/include/freerdp/codec/nsc.h +++ b/include/freerdp/codec/nsc.h @@ -42,9 +42,25 @@ struct _NSC_STREAM }; typedef struct _NSC_STREAM NSC_STREAM; +struct _NSC_MESSAGE +{ + int x; + int y; + UINT32 width; + UINT32 height; + BYTE* data; + int scanline; + UINT32 MaxPlaneSize; + BYTE* PlaneBuffers[5]; + UINT32 OrgByteCount[4]; + UINT32 PlaneByteCount[4]; +}; +typedef struct _NSC_MESSAGE NSC_MESSAGE; + typedef struct _NSC_CONTEXT_PRIV NSC_CONTEXT_PRIV; typedef struct _NSC_CONTEXT NSC_CONTEXT; + struct _NSC_CONTEXT { UINT32 OrgByteCount[4]; /* original byte length of luma, chroma orange, chroma green, alpha variable in order */ @@ -52,15 +68,15 @@ struct _NSC_CONTEXT UINT16 bpp; UINT16 width; UINT16 height; - BYTE* bmpdata; /* final argb values in little endian order */ - UINT32 bmpdata_length; /* the maximum length of the buffer that bmpdata points to */ + BYTE* BitmapData; /* final argb values in little endian order */ + UINT32 BitmapDataLength; /* the maximum length of the buffer that bmpdata points to */ RDP_PIXEL_FORMAT pixel_format; /* color palette allocated by the application */ const BYTE* palette; void (*decode)(NSC_CONTEXT* context); - void (*encode)(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride); + void (*encode)(NSC_CONTEXT* context, BYTE* BitmapData, int rowstride); NSC_CONTEXT_PRIV* priv; }; @@ -73,6 +89,11 @@ FREERDP_API void nsc_compose_message(NSC_CONTEXT* context, wStream* s, BYTE* bmpdata, int width, int height, int rowstride); FREERDP_API void nsc_context_free(NSC_CONTEXT* context); +FREERDP_API NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y, + int width, int height, int scanline, int* numMessages, int maxDataSize); +FREERDP_API int nsc_write_message(NSC_CONTEXT* context, wStream* s, NSC_MESSAGE* message); +FREERDP_API int nsc_message_free(NSC_CONTEXT* context, NSC_MESSAGE* message); + #ifdef __cplusplus } #endif diff --git a/include/freerdp/codec/rfx.h b/include/freerdp/codec/rfx.h index d3ba0536a..254cadfb5 100644 --- a/include/freerdp/codec/rfx.h +++ b/include/freerdp/codec/rfx.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -50,18 +51,36 @@ struct _RFX_TILE { UINT16 x; UINT16 y; + int width; + int height; BYTE* data; + int scanline; + + BYTE quantIdxY; + BYTE quantIdxCb; + BYTE quantIdxCr; + UINT16 xIdx; + UINT16 yIdx; + UINT16 YLen; + UINT16 CbLen; + UINT16 CrLen; + BYTE* YData; + BYTE* CbData; + BYTE* CrData; }; typedef struct _RFX_TILE RFX_TILE; struct _RFX_MESSAGE { + UINT32 frameIdx; + /** * The rects array represents the updated region of the frame. The UI * requires to clip drawing destination base on the union of the rects. */ - UINT16 num_rects; + UINT16 numRects; RFX_RECT* rects; + BOOL freeRects; /** * The tiles array represents the actual frame data. Each tile is always @@ -69,15 +88,35 @@ struct _RFX_MESSAGE * rects described above) are valid. Pixels outside of the region may * contain arbitrary data. */ - UINT16 num_tiles; + UINT16 numTiles; RFX_TILE** tiles; + + UINT16 numQuant; + UINT32* quantVals; + + UINT32 tilesDataSize; + + BOOL freeArray; }; typedef struct _RFX_MESSAGE RFX_MESSAGE; typedef struct _RFX_CONTEXT_PRIV RFX_CONTEXT_PRIV; +enum _RFX_STATE +{ + RFX_STATE_INITIAL, + RFX_STATE_SERVER_UNINITIALIZED, + RFX_STATE_SEND_HEADERS, + RFX_STATE_SEND_FRAME_DATA, + RFX_STATE_FRAME_DATA_SENT, + RFX_STATE_FINAL +}; +typedef enum _RFX_STATE RFX_STATE; + struct _RFX_CONTEXT { + RFX_STATE state; + UINT16 flags; UINT16 properties; UINT16 width; @@ -93,19 +132,20 @@ struct _RFX_CONTEXT const BYTE* palette; /* temporary data within a frame */ - UINT32 frame_idx; - BOOL header_processed; - BYTE num_quants; + UINT32 frameIdx; + BYTE numQuant; UINT32* quants; - BYTE quant_idx_y; - BYTE quant_idx_cb; - BYTE quant_idx_cr; + BYTE quantIdxY; + BYTE quantIdxCb; + BYTE quantIdxCr; /* routines */ void (*quantization_decode)(INT16* buffer, const UINT32* quantization_values); void (*quantization_encode)(INT16* buffer, const UINT32* quantization_values); void (*dwt_2d_decode)(INT16* buffer, INT16* dwt_buffer); void (*dwt_2d_encode)(INT16* buffer, INT16* dwt_buffer); + int (*rlgr_decode)(RLGR_MODE mode, const BYTE* data, int data_size, INT16* buffer, int buffer_size); + int (*rlgr_encode)(RLGR_MODE mode, const INT16* data, int data_size, BYTE* buffer, int buffer_size); /* private definitions */ RFX_CONTEXT_PRIV* priv; @@ -128,6 +168,12 @@ FREERDP_API void rfx_compose_message_header(RFX_CONTEXT* context, wStream* s); FREERDP_API void rfx_compose_message(RFX_CONTEXT* context, wStream* s, const RFX_RECT* rects, int num_rects, BYTE* image_data, int width, int height, int rowstride); +FREERDP_API RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, + int numRects, BYTE* data, int width, int height, int scanline); +FREERDP_API RFX_MESSAGE* rfx_encode_messages(RFX_CONTEXT* context, const RFX_RECT* rects, int numRects, + BYTE* data, int width, int height, int scanline, int* numMessages, int maxDataSize); +FREERDP_API void rfx_write_message(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* message); + #ifdef __cplusplus } #endif diff --git a/include/freerdp/crypto/tls.h b/include/freerdp/crypto/tls.h index c396679b3..7e9aca995 100644 --- a/include/freerdp/crypto/tls.h +++ b/include/freerdp/crypto/tls.h @@ -61,6 +61,7 @@ FREERDP_API int tls_write_all(rdpTls* tls, BYTE* data, int length); FREERDP_API int tls_wait_read(rdpTls* tls); FREERDP_API int tls_wait_write(rdpTls* tls); +FREERDP_API BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname); FREERDP_API BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname); FREERDP_API void tls_print_certificate_error(char* hostname, char* fingerprint, char* hosts_file); FREERDP_API void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count); diff --git a/include/freerdp/error.h b/include/freerdp/error.h old mode 100644 new mode 100755 index 8b0abd8f0..3c00b5c13 --- a/include/freerdp/error.h +++ b/include/freerdp/error.h @@ -20,6 +20,10 @@ #ifndef FREERDP_ERROR_H #define FREERDP_ERROR_H +#include + +#include + #ifdef __cplusplus extern "C" { #endif @@ -128,6 +132,9 @@ extern "C" { #define ERRINFO_SUCCESS 0x00000000 #define ERRINFO_NONE 0xFFFFFFFF +FREERDP_API const char* freerdp_get_error_info_string(UINT32 code); +FREERDP_API const char* freerdp_get_error_info_name(UINT32 code); + /** * This static variable holds an error code if the return value from connect is FALSE. * This variable is always set to 0 in the beginning of the connect sequence. @@ -135,7 +142,7 @@ extern "C" { * The value can hold one of the defined error codes below OR an error according to errno */ -extern int connectErrorCode; +FREERDP_API extern int connectErrorCode; #define ERRORSTART 10000 #define PREECONNECTERROR ERRORSTART + 1 diff --git a/include/freerdp/event.h b/include/freerdp/event.h index 7753e133d..3f6d51196 100644 --- a/include/freerdp/event.h +++ b/include/freerdp/event.h @@ -41,6 +41,20 @@ DEFINE_EVENT_BEGIN(ResizeWindow) int width; int height; DEFINE_EVENT_END(ResizeWindow) + +DEFINE_EVENT_BEGIN(PanningChange) + int XPan; + int YPan; +DEFINE_EVENT_END(PanningChange) + +DEFINE_EVENT_BEGIN(ScalingFactorChange) + double ScalingFactor; +DEFINE_EVENT_END(ScalingFactorChange) + +DEFINE_EVENT_BEGIN(LocalResizeWindow) + int width; + int height; +DEFINE_EVENT_END(LocalResizeWindow) DEFINE_EVENT_BEGIN(EmbedWindow) BOOL embed; @@ -59,6 +73,20 @@ DEFINE_EVENT_BEGIN(Terminate) int code; DEFINE_EVENT_END(Terminate) +DEFINE_EVENT_BEGIN(ConnectionResult) + int result; +DEFINE_EVENT_END(ConnectionResult) + +DEFINE_EVENT_BEGIN(ChannelConnected) + const char* name; + void* pInterface; +DEFINE_EVENT_END(ChannelConnected) + +DEFINE_EVENT_BEGIN(ChannelDisconnected) + const char* name; + void* pInterface; +DEFINE_EVENT_END(ChannelDisconnected) + #ifdef __cplusplus } #endif diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index 214c2f719..e3ce2bf84 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -66,9 +66,6 @@ typedef int (*pLogonErrorInfo)(freerdp* instance, UINT32 data, UINT32 type); typedef int (*pSendChannelData)(freerdp* instance, int channelId, BYTE* data, int size); typedef int (*pReceiveChannelData)(freerdp* instance, int channelId, BYTE* data, int size, int flags, int total_size); -typedef int (*pOnChannelConnected)(freerdp* instance, const char* name, void* pInterface); -typedef int (*pOnChannelDisconnected)(freerdp* instance, const char* name, void* pInterface); - /** * Defines the context for a given instance of RDP connection. * It is embedded in the rdp_freerdp structure, and allocated by a call to freerdp_context_new(). @@ -208,9 +205,6 @@ struct rdp_freerdp This is called by freerdp_channel_process() (if not NULL). Clients will typically use a function that calls freerdp_channels_data() to perform the needed tasks. */ - ALIGN64 pOnChannelConnected OnChannelConnected; - ALIGN64 pOnChannelDisconnected OnChannelDisconnected; - UINT64 paddingE[80 - 66]; /* 66 */ }; diff --git a/include/freerdp/listener.h b/include/freerdp/listener.h index 49cd12217..9ae1156d6 100644 --- a/include/freerdp/listener.h +++ b/include/freerdp/listener.h @@ -34,6 +34,7 @@ extern "C" { typedef BOOL (*psListenerOpen)(freerdp_listener* instance, const char* bind_address, UINT16 port); typedef BOOL (*psListenerOpenLocal)(freerdp_listener* instance, const char* path); typedef BOOL (*psListenerGetFileDescriptor)(freerdp_listener* instance, void** rfds, int* rcount); +typedef int (*psListenerGetEventHandles)(freerdp_listener* instance, HANDLE* events, DWORD* nCount); typedef BOOL (*psListenerCheckFileDescriptor)(freerdp_listener* instance); typedef void (*psListenerClose)(freerdp_listener* instance); typedef void (*psPeerAccepted)(freerdp_listener* instance, freerdp_peer* client); @@ -50,6 +51,7 @@ struct rdp_freerdp_listener psListenerOpen Open; psListenerOpenLocal OpenLocal; psListenerGetFileDescriptor GetFileDescriptor; + psListenerGetEventHandles GetEventHandles; psListenerCheckFileDescriptor CheckFileDescriptor; psListenerClose Close; diff --git a/include/freerdp/locale/keyboard.h b/include/freerdp/locale/keyboard.h index 32a7ed5fe..147067d8e 100644 --- a/include/freerdp/locale/keyboard.h +++ b/include/freerdp/locale/keyboard.h @@ -205,6 +205,7 @@ extern "C" { FREERDP_API DWORD freerdp_keyboard_init(DWORD keyboardLayoutId); FREERDP_API RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types); +FREERDP_API void freerdp_keyboard_layouts_free(RDP_KEYBOARD_LAYOUT* layouts); FREERDP_API const char* freerdp_keyboard_get_layout_name_from_id(DWORD keyboardLayoutId); FREERDP_API DWORD freerdp_keyboard_get_layout_id_from_name(const char* name); FREERDP_API DWORD freerdp_keyboard_get_rdp_scancode_from_x11_keycode(DWORD keycode); diff --git a/include/freerdp/peer.h b/include/freerdp/peer.h index 6279c92bc..e447ba014 100644 --- a/include/freerdp/peer.h +++ b/include/freerdp/peer.h @@ -33,6 +33,7 @@ typedef void (*psPeerContextFree)(freerdp_peer* client, rdpContext* context); typedef BOOL (*psPeerInitialize)(freerdp_peer* client); typedef BOOL (*psPeerGetFileDescriptor)(freerdp_peer* client, void** rfds, int* rcount); +typedef HANDLE (*psPeerGetEventHandle)(freerdp_peer* client); typedef BOOL (*psPeerCheckFileDescriptor)(freerdp_peer* client); typedef BOOL (*psPeerClose)(freerdp_peer* client); typedef void (*psPeerDisconnect)(freerdp_peer* client); @@ -60,6 +61,7 @@ struct rdp_freerdp_peer psPeerInitialize Initialize; psPeerGetFileDescriptor GetFileDescriptor; + psPeerGetEventHandle GetEventHandle; psPeerCheckFileDescriptor CheckFileDescriptor; psPeerClose Close; psPeerDisconnect Disconnect; diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index eb3541cf2..b9ca69342 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -609,6 +609,9 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_WmClass 1549 #define FreeRDP_EmbeddedWindow 1550 #define FreeRDP_SmartSizing 1551 +#define FreeRDP_XPan 1552 +#define FreeRDP_YPan 1553 +#define FreeRDP_ScalingFactor 1554 #define FreeRDP_SoftwareGdi 1601 #define FreeRDP_LocalConnection 1602 #define FreeRDP_AuthenticationOnly 1603 @@ -630,6 +633,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_GatewayDomain 1989 #define FreeRDP_GatewayCredentialsSource 1990 #define FreeRDP_GatewayUseSameCredentials 1991 +#define FreeRDP_GatewayEnabled 1992 #define FreeRDP_RemoteApplicationMode 2112 #define FreeRDP_RemoteApplicationName 2113 #define FreeRDP_RemoteApplicationIcon 2114 @@ -677,6 +681,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_UnicodeInput 2629 #define FreeRDP_FastPathInput 2630 #define FreeRDP_MultiTouchInput 2631 +#define FreeRDP_MultiTouchGestures 2632 #define FreeRDP_BrushSupportLevel 2688 #define FreeRDP_GlyphSupportLevel 2752 #define FreeRDP_GlyphCache 2753 @@ -976,7 +981,10 @@ struct rdp_settings ALIGN64 char* WmClass; /* 1549 */ ALIGN64 BOOL EmbeddedWindow; /* 1550 */ ALIGN64 BOOL SmartSizing; /* 1551 */ - UINT64 padding1600[1600 - 1552]; /* 1552 */ + ALIGN64 int XPan; /* 1552 */ + ALIGN64 int YPan; /* 1553 */ + ALIGN64 double ScalingFactor; /* 1554 */ + UINT64 padding1600[1600 - 1555]; /* 1555 */ /* Miscellaneous */ ALIGN64 BOOL SoftwareGdi; /* 1601 */ @@ -1012,7 +1020,7 @@ struct rdp_settings */ /* Gateway */ - ALIGN64 BOOL GatewayUsageMethod; /* 1984 */ + ALIGN64 UINT32 GatewayUsageMethod; /* 1984 */ ALIGN64 UINT32 GatewayPort; /* 1985 */ ALIGN64 char* GatewayHostname; /* 1986 */ ALIGN64 char* GatewayUsername; /* 1987 */ @@ -1020,7 +1028,8 @@ struct rdp_settings ALIGN64 char* GatewayDomain; /* 1989 */ ALIGN64 UINT32 GatewayCredentialsSource; /* 1990 */ ALIGN64 BOOL GatewayUseSameCredentials; /* 1991 */ - UINT64 padding2048[2048 - 1992]; /* 1992 */ + ALIGN64 BOOL GatewayEnabled; /* 1992 */ + UINT64 padding2048[2048 - 1993]; /* 1993 */ UINT64 padding2112[2112 - 2048]; /* 2048 */ /** @@ -1101,7 +1110,8 @@ struct rdp_settings ALIGN64 BOOL UnicodeInput; /* 2629 */ ALIGN64 BOOL FastPathInput; /* 2630 */ ALIGN64 BOOL MultiTouchInput; /* 2631 */ - UINT64 padding2688[2688 - 2632]; /* 2632 */ + ALIGN64 BOOL MultiTouchGestures; /* 2632 */ + UINT64 padding2688[2688 - 2633]; /* 2633 */ /* Brush Capabilities */ ALIGN64 UINT32 BrushSupportLevel; /* 2688 */ @@ -1310,6 +1320,9 @@ FREERDP_API void freerdp_dynamic_channel_collection_free(rdpSettings* settings); FREERDP_API BOOL freerdp_get_param_bool(rdpSettings* settings, int id); FREERDP_API int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param); +FREERDP_API int freerdp_get_param_int(rdpSettings* settings, int id); +FREERDP_API int freerdp_set_param_int(rdpSettings* settings, int id, int param); + FREERDP_API UINT32 freerdp_get_param_uint32(rdpSettings* settings, int id); FREERDP_API int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param); @@ -1319,6 +1332,9 @@ FREERDP_API int freerdp_set_param_uint64(rdpSettings* settings, int id, UINT64 p FREERDP_API char* freerdp_get_param_string(rdpSettings* settings, int id); FREERDP_API int freerdp_set_param_string(rdpSettings* settings, int id, char* param); +FREERDP_API double freerdp_get_param_double(rdpSettings* settings, int id); +FREERDP_API int freerdp_set_param_double(rdpSettings* settings, int id, double param); + #ifdef __cplusplus } #endif diff --git a/include/freerdp/update.h b/include/freerdp/update.h index db6f36bb9..a6aa8caa9 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -134,6 +134,14 @@ enum SURFCMD_FRAMEACTION SURFACECMD_FRAMEACTION_END = 0x0001 }; +struct _SURFACE_FRAME +{ + UINT32 frameId; + UINT32 commandCount; + SURFACE_BITS_COMMAND* commands; +}; +typedef struct _SURFACE_FRAME SURFACE_FRAME; + /* defined inside libfreerdp-core */ typedef struct rdp_update_proxy rdpUpdateProxy; diff --git a/include/freerdp/utils/stopwatch.h b/include/freerdp/utils/stopwatch.h index 843d1bd12..af6aa1ee3 100644 --- a/include/freerdp/utils/stopwatch.h +++ b/include/freerdp/utils/stopwatch.h @@ -20,17 +20,15 @@ #ifndef FREERDP_UTILS_STOPWATCH_H #define FREERDP_UTILS_STOPWATCH_H -#include - #include #include struct _STOPWATCH { - clock_t start; - clock_t end; - double elapsed; - clock_t count; + UINT64 start; + UINT64 end; + UINT64 elapsed; + UINT32 count; }; typedef struct _STOPWATCH STOPWATCH; diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index 6dccb0771..bbc714b15 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -59,9 +59,11 @@ if(MONOLITHIC_BUILD) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT libraries) + if(NOT WITH_WAYK) + install(TARGETS ${MODULE_NAME} + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT libraries) + endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp") endif() diff --git a/libfreerdp/cache/bitmap.c b/libfreerdp/cache/bitmap.c index a1136a08a..fcd653b5f 100644 --- a/libfreerdp/cache/bitmap.c +++ b/libfreerdp/cache/bitmap.c @@ -40,6 +40,8 @@ void update_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt) bitmap = offscreen_cache_get(cache->offscreen, memblt->cacheIndex); else bitmap = bitmap_cache_get(cache->bitmap, (BYTE) memblt->cacheId, memblt->cacheIndex); + /* XP-SP2 servers sometimes ask for cached bitmaps they've never defined. */ + if (bitmap == NULL) return; memblt->bitmap = bitmap; IFCALL(cache->bitmap->MemBlt, context, memblt); @@ -56,6 +58,8 @@ void update_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) bitmap = offscreen_cache_get(cache->offscreen, mem3blt->cacheIndex); else bitmap = bitmap_cache_get(cache->bitmap, (BYTE) mem3blt->cacheId, mem3blt->cacheIndex); + /* XP-SP2 servers sometimes ask for cached bitmaps they've never defined. */ + if (bitmap == NULL) return; style = brush->style; diff --git a/libfreerdp/cache/glyph.c b/libfreerdp/cache/glyph.c index 847ac3849..14f2f69dd 100644 --- a/libfreerdp/cache/glyph.c +++ b/libfreerdp/cache/glyph.c @@ -500,6 +500,7 @@ void glyph_cache_free(rdpGlyphCache* glyph_cache) Glyph_Free(glyph_cache->context, glyph); free(glyph->aj); free(glyph); + glyph_cache->glyphCache[i].entries[j] = NULL; } } free(glyph_cache->glyphCache[i].entries); @@ -509,6 +510,7 @@ void glyph_cache_free(rdpGlyphCache* glyph_cache) { fragment = glyph_cache->fragCache.entries[i].fragment; free(fragment); + glyph_cache->fragCache.entries[i].fragment = NULL; } free(glyph_cache->fragCache.entries); diff --git a/libfreerdp/cache/pointer.c b/libfreerdp/cache/pointer.c index 484c2985b..57bc3a4ef 100644 --- a/libfreerdp/cache/pointer.c +++ b/libfreerdp/cache/pointer.c @@ -68,9 +68,18 @@ void update_pointer_color(rdpContext* context, POINTER_COLOR_UPDATE* pointer_col pointer->height = pointer_color->height; pointer->lengthAndMask = pointer_color->lengthAndMask; pointer->lengthXorMask = pointer_color->lengthXorMask; - pointer->xorMaskData = pointer_color->xorMaskData; - pointer->andMaskData = pointer_color->andMaskData; + if (pointer->lengthAndMask && pointer_color->xorMaskData) + { + pointer->andMaskData = (BYTE*) malloc(pointer->lengthAndMask); + CopyMemory(pointer->andMaskData, pointer_color->andMaskData, pointer->lengthAndMask); + } + + if (pointer->lengthXorMask && pointer_color->xorMaskData) + { + pointer->xorMaskData = (BYTE*) malloc(pointer->lengthXorMask); + CopyMemory(pointer->xorMaskData, pointer_color->xorMaskData, pointer->lengthXorMask); + } pointer->New(context, pointer); pointer_cache_put(cache->pointer, pointer_color->cacheIndex, pointer); Pointer_Set(context, pointer); @@ -202,7 +211,10 @@ void pointer_cache_free(rdpPointerCache* pointer_cache) pointer = pointer_cache->entries[i]; if (pointer != NULL) + { Pointer_Free(pointer_cache->update->context, pointer); + pointer_cache->entries[i] = NULL; + } } free(pointer_cache->entries); diff --git a/libfreerdp/codec/CMakeLists.txt b/libfreerdp/codec/CMakeLists.txt index 8895848b2..19533017b 100644 --- a/libfreerdp/codec/CMakeLists.txt +++ b/libfreerdp/codec/CMakeLists.txt @@ -20,9 +20,10 @@ set(MODULE_PREFIX "FREERDP_CODEC") set(${MODULE_PREFIX}_SRCS dsp.c - bitmap.c color.c audio.c + bitmap_decode.c + bitmap_encode.c rfx_bitstream.h rfx_constants.h rfx_decode.c diff --git a/libfreerdp/codec/bitmap.c b/libfreerdp/codec/bitmap_decode.c similarity index 99% rename from libfreerdp/codec/bitmap.c rename to libfreerdp/codec/bitmap_decode.c index 598017081..431a213a8 100644 --- a/libfreerdp/codec/bitmap.c +++ b/libfreerdp/codec/bitmap_decode.c @@ -1,6 +1,6 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Compressed Bitmap + * Bitmap Decompression * * Copyright 2011 Jay Sorg * diff --git a/libfreerdp/codec/bitmap_encode.c b/libfreerdp/codec/bitmap_encode.c new file mode 100644 index 000000000..84ab3b14a --- /dev/null +++ b/libfreerdp/codec/bitmap_encode.c @@ -0,0 +1,1724 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Bitmap Compression + * + * Copyright 2004-2012 Jay Sorg + * + * 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 + +#define GETPIXEL8(d, x, y, w) (*(((unsigned char*)d) + ((y) * (w) + (x)))) +#define GETPIXEL16(d, x, y, w) (*(((unsigned short*)d) + ((y) * (w) + (x)))) +#define GETPIXEL32(d, x, y, w) (*(((unsigned int*)d) + ((y) * (w) + (x)))) + +/*****************************************************************************/ +#define IN_PIXEL8(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ + { \ + if (in_ptr == 0) \ + { \ + in_pixel = 0; \ + } \ + else if (in_x < in_w) \ + { \ + in_pixel = GETPIXEL8(in_ptr, in_x, in_y, in_w); \ + } \ + else \ + { \ + in_pixel = in_last_pixel; \ + } \ + } + +/*****************************************************************************/ +#define IN_PIXEL16(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ + { \ + if (in_ptr == 0) \ + { \ + in_pixel = 0; \ + } \ + else if (in_x < in_w) \ + { \ + in_pixel = GETPIXEL16(in_ptr, in_x, in_y, in_w); \ + } \ + else \ + { \ + in_pixel = in_last_pixel; \ + } \ + } + +/*****************************************************************************/ +#define IN_PIXEL32(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ + { \ + if (in_ptr == 0) \ + { \ + in_pixel = 0; \ + } \ + else if (in_x < in_w) \ + { \ + in_pixel = GETPIXEL32(in_ptr, in_x, in_y, in_w); \ + } \ + else \ + { \ + in_pixel = in_last_pixel; \ + } \ + } + +/*****************************************************************************/ +/* color */ +#define OUT_COLOR_COUNT1(in_count, in_s, in_data) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x3 << 5) | in_count; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT8(in_s, in_data); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x60); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT8(in_s, in_data); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf3); \ + Stream_Write_UINT16(in_s, in_count); \ + Stream_Write_UINT8(in_s, in_data); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* color */ +#define OUT_COLOR_COUNT2(in_count, in_s, in_data) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x3 << 5) | in_count; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT16(in_s, in_data); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x60); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT16(in_s, in_data); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf3); \ + Stream_Write_UINT16(in_s, in_count); \ + Stream_Write_UINT16(in_s, in_data); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* color */ +#define OUT_COLOR_COUNT3(in_count, in_s, in_data) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x3 << 5) | in_count; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT8(in_s, in_data & 0xFF); \ + Stream_Write_UINT8(in_s, (in_data >> 8) & 0xFF); \ + Stream_Write_UINT8(in_s, (in_data >> 16) & 0xFF); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x60); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT8(in_s, in_data & 0xFF); \ + Stream_Write_UINT8(in_s, (in_data >> 8) & 0xFF); \ + Stream_Write_UINT8(in_s, (in_data >> 16) & 0xFF); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf3); \ + Stream_Write_UINT16(in_s, in_count); \ + Stream_Write_UINT8(in_s, in_data & 0xFF); \ + Stream_Write_UINT8(in_s, (in_data >> 8) & 0xFF); \ + Stream_Write_UINT8(in_s, (in_data >> 16) & 0xFF); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* copy */ +#define OUT_COPY_COUNT1(in_count, in_s, in_data) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x4 << 5) | in_count; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write(in_s, Stream_Buffer(in_data), in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x80); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write(in_s, Stream_Buffer(in_data), in_count); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf4); \ + Stream_Write_UINT16(in_s, in_count); \ + Stream_Write(in_s, Stream_Buffer(in_data), in_count); \ + } \ + } \ + in_count = 0; \ + Stream_SetPosition(in_data, 0); \ + } + +/*****************************************************************************/ +/* copy */ +#define OUT_COPY_COUNT2(in_count, in_s, in_data) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x4 << 5) | in_count; \ + Stream_Write_UINT8(in_s, temp); \ + temp = in_count * 2; \ + Stream_Write(in_s, Stream_Buffer(in_data), temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x80); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + temp = in_count * 2; \ + Stream_Write(in_s, Stream_Buffer(in_data), temp); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf4); \ + Stream_Write_UINT16(in_s, in_count); \ + temp = in_count * 2; \ + Stream_Write(in_s, Stream_Buffer(in_data), temp); \ + } \ + } \ + in_count = 0; \ + Stream_SetPosition(in_data, 0); \ + } + +/*****************************************************************************/ +/* copy */ +#define OUT_COPY_COUNT3(in_count, in_s, in_data) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x4 << 5) | in_count; \ + Stream_Write_UINT8(in_s, temp); \ + temp = in_count * 3; \ + Stream_Write(in_s, Stream_Pointer(in_data), temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x80); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + temp = in_count * 3; \ + Stream_Write(in_s, Stream_Pointer(in_data), temp); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf4); \ + Stream_Write_UINT16(in_s, in_count); \ + temp = in_count * 3; \ + Stream_Write(in_s, Stream_Pointer(in_data), temp); \ + } \ + } \ + in_count = 0; \ + Stream_SetPosition(in_data, 0); \ + } + +/*****************************************************************************/ +/* bicolor */ +#define OUT_BICOLOR_COUNT1(in_count, in_s, in_color1, in_color2) \ + { \ + if (in_count > 0) \ + { \ + if (in_count / 2 < 16) \ + { \ + temp = (0xe << 4) | (in_count / 2); \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT8(in_s, in_color1); \ + Stream_Write_UINT8(in_s, in_color2); \ + } \ + else if (in_count / 2 < 256 + 16) \ + { \ + Stream_Write_UINT8(in_s, 0xe0); \ + temp = in_count / 2 - 16; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT8(in_s, in_color1); \ + Stream_Write_UINT8(in_s, in_color2); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf8); \ + temp = in_count / 2; \ + Stream_Write_UINT16(in_s, temp); \ + Stream_Write_UINT8(in_s, in_color1); \ + Stream_Write_UINT8(in_s, in_color2); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* bicolor */ +#define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \ + { \ + if (in_count > 0) \ + { \ + if (in_count / 2 < 16) \ + { \ + temp = (0xe << 4) | (in_count / 2); \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT16(in_s, in_color1); \ + Stream_Write_UINT16(in_s, in_color2); \ + } \ + else if (in_count / 2 < 256 + 16) \ + { \ + Stream_Write_UINT8(in_s, 0xe0); \ + temp = in_count / 2 - 16; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT16(in_s, in_color1); \ + Stream_Write_UINT16(in_s, in_color2); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf8); \ + temp = in_count / 2; \ + Stream_Write_UINT16(in_s, temp); \ + Stream_Write_UINT16(in_s, in_color1); \ + Stream_Write_UINT16(in_s, in_color2); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* bicolor */ +#define OUT_BICOLOR_COUNT3(in_count, in_s, in_color1, in_color2) \ + { \ + if (in_count > 0) \ + { \ + if (in_count / 2 < 16) \ + { \ + temp = (0xe << 4) | (in_count / 2); \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT8(in_s, in_color1 & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color1 >> 8) & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color1 >> 16) & 0xFF); \ + Stream_Write_UINT8(in_s, in_color2 & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color2 >> 8) & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color2 >> 16) & 0xFF); \ + } \ + else if (in_count / 2 < 256 + 16) \ + { \ + Stream_Write_UINT8(in_s, 0xe0); \ + temp = in_count / 2 - 16; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write_UINT8(in_s, in_color1 & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color1 >> 8) & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color1 >> 16) & 0xFF); \ + Stream_Write_UINT8(in_s, in_color2 & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color2 >> 8) & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color2 >> 16) & 0xFF); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf8); \ + temp = in_count / 2; \ + Stream_Write_UINT16(in_s, temp); \ + Stream_Write_UINT8(in_s, in_color1 & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color1 >> 8) & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color1 >> 16) & 0xFF); \ + Stream_Write_UINT8(in_s, in_color2 & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color2 >> 8) & 0xFF); \ + Stream_Write_UINT8(in_s, (in_color2 >> 16) & 0xFF); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* fill */ +#define OUT_FILL_COUNT1(in_count, in_s) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + Stream_Write_UINT8(in_s, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x0); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf0); \ + Stream_Write_UINT16(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* fill */ +#define OUT_FILL_COUNT2(in_count, in_s) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + Stream_Write_UINT8(in_s, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x0); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf0); \ + Stream_Write_UINT16(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* fill */ +#define OUT_FILL_COUNT3(in_count, in_s) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + Stream_Write_UINT8(in_s, in_count); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x0); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf0); \ + Stream_Write_UINT16(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* mix */ +#define OUT_MIX_COUNT1(in_count, in_s) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x1 << 5) | in_count; \ + Stream_Write_UINT8(in_s, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x20); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf1); \ + Stream_Write_UINT16(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* mix */ +#define OUT_MIX_COUNT2(in_count, in_s) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x1 << 5) | in_count; \ + Stream_Write_UINT8(in_s, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x20); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf1); \ + Stream_Write_UINT16(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* mix */ +#define OUT_MIX_COUNT3(in_count, in_s) \ + { \ + if (in_count > 0) \ + { \ + if (in_count < 32) \ + { \ + temp = (0x1 << 5) | in_count; \ + Stream_Write_UINT8(in_s, temp); \ + } \ + else if (in_count < 256 + 32) \ + { \ + Stream_Write_UINT8(in_s, 0x20); \ + temp = in_count - 32; \ + Stream_Write_UINT8(in_s, temp); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf1); \ + Stream_Write_UINT16(in_s, in_count); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* fom */ +#define OUT_FOM_COUNT1(in_count, in_s, in_mask, in_mask_len) \ + { \ + if (in_count > 0) \ + { \ + if ((in_count % 8) == 0 && in_count < 249) \ + { \ + temp = (0x2 << 5) | (in_count / 8); \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write(in_s, in_mask, in_mask_len); \ + } \ + else if (in_count < 256) \ + { \ + Stream_Write_UINT8(in_s, 0x40); \ + temp = in_count - 1; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write(in_s, in_mask, in_mask_len); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf2); \ + Stream_Write_UINT16(in_s, in_count); \ + Stream_Write(in_s, in_mask, in_mask_len); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* fom */ +#define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \ + { \ + if (in_count > 0) \ + { \ + if ((in_count % 8) == 0 && in_count < 249) \ + { \ + temp = (0x2 << 5) | (in_count / 8); \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write(in_s, in_mask, in_mask_len); \ + } \ + else if (in_count < 256) \ + { \ + Stream_Write_UINT8(in_s, 0x40); \ + temp = in_count - 1; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write(in_s, in_mask, in_mask_len); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf2); \ + Stream_Write_UINT16(in_s, in_count); \ + Stream_Write(in_s, in_mask, in_mask_len); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +/* fill or mix (fom) */ +#define OUT_FOM_COUNT3(in_count, in_s, in_mask, in_mask_len) \ + { \ + if (in_count > 0) \ + { \ + if ((in_count % 8) == 0 && in_count < 249) \ + { \ + temp = (0x2 << 5) | (in_count / 8); \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write(in_s, in_mask, in_mask_len); \ + } \ + else if (in_count < 256) \ + { \ + Stream_Write_UINT8(in_s, 0x40); \ + temp = in_count - 1; \ + Stream_Write_UINT8(in_s, temp); \ + Stream_Write(in_s, in_mask, in_mask_len); \ + } \ + else \ + { \ + Stream_Write_UINT8(in_s, 0xf2); \ + Stream_Write_UINT16(in_s, in_count); \ + Stream_Write(in_s, in_mask, in_mask_len); \ + } \ + } \ + in_count = 0; \ + } + +/*****************************************************************************/ +#define TEST_FILL \ + ((last_line == 0 && pixel == 0) || \ + (last_line != 0 && pixel == ypixel)) +#define TEST_MIX \ + ((last_line == 0 && pixel == mix) || \ + (last_line != 0 && pixel == (ypixel ^ mix))) +#define TEST_FOM (TEST_FILL || TEST_MIX) +#define TEST_COLOR (pixel == last_pixel) +#define TEST_BICOLOR \ + ( \ + (pixel != last_pixel) && \ + ( \ + (!bicolor_spin && pixel == bicolor1 && last_pixel == bicolor2) || \ + (bicolor_spin && pixel == bicolor2 && last_pixel == bicolor1) \ + ) \ + ) +#define RESET_COUNTS \ + { \ + bicolor_count = 0; \ + fill_count = 0; \ + color_count = 0; \ + mix_count = 0; \ + fom_count = 0; \ + fom_mask_len = 0; \ + bicolor_spin = 0; \ + } + +/*****************************************************************************/ +int freerdp_bitmap_compress(char* in_data, int width, int height, + wStream* s, int bpp, int byte_limit, int start_line, wStream* temp_s, int e) +{ + char *line; + char *last_line; + char fom_mask[8192]; /* good for up to 64K bitmap */ + int lines_sent; + int pixel; + int count; + int color_count; + int last_pixel; + int bicolor_count; + int bicolor1; + int bicolor2; + int bicolor_spin; + int end; + int i; + int out_count; + int ypixel; + int last_ypixel; + int fill_count; + int mix_count; + int mix; + int fom_count; + int fom_mask_len; + int temp; /* used in macros */ + + Stream_SetPosition(temp_s, 0); + fom_mask_len = 0; + last_line = 0; + lines_sent = 0; + end = width + e; + count = 0; + color_count = 0; + last_pixel = 0; + last_ypixel = 0; + bicolor_count = 0; + bicolor1 = 0; + bicolor2 = 0; + bicolor_spin = 0; + fill_count = 0; + mix_count = 0; + fom_count = 0; + + if (bpp == 8) + { + mix = 0xFF; + out_count = end; + line = in_data + width * start_line; + + while (start_line >= 0 && out_count < 32768) + { + i = Stream_GetPosition(s) + count; + + if (i - color_count >= byte_limit && + i - bicolor_count >= byte_limit && + i - fill_count >= byte_limit && + i - mix_count >= byte_limit && + i - fom_count >= byte_limit) + { + break; + } + + out_count += end; + + for (i = 0; i < end; i++) + { + /* read next pixel */ + IN_PIXEL8(line, i, 0, width, last_pixel, pixel); + IN_PIXEL8(last_line, i, 0, width, last_ypixel, ypixel); + + if (!TEST_FILL) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FILL_COUNT1(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + } + + if (!TEST_MIX) + { + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_MIX_COUNT1(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + } + + if (!TEST_COLOR) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_COLOR_COUNT1(color_count, s, last_pixel); + RESET_COUNTS; + } + + color_count = 0; + } + + if (!TEST_BICOLOR) + { + if (bicolor_count > 3 && + bicolor_count >= fill_count && + bicolor_count >= color_count && + bicolor_count >= mix_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); + } + + RESET_COUNTS; + } + + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = 0; + } + + if (!TEST_FOM) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + if (TEST_FILL) + { + fill_count++; + } + + if (TEST_MIX) + { + mix_count++; + } + + if (TEST_COLOR) + { + color_count++; + } + + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + + fom_count++; + } + + Stream_Write_UINT8(temp_s, pixel); + count++; + last_pixel = pixel; + last_ypixel = ypixel; + } + + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FILL_COUNT1(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_MIX_COUNT1(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + last_line = line; + line = line - width; + start_line--; + lines_sent++; + } + + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FILL_COUNT1(fill_count, s); + } + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_MIX_COUNT1(mix_count, s); + } + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_COLOR_COUNT1(color_count, s, last_pixel); + } + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor2, bicolor1); + } + + count -= bicolor_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_BICOLOR_COUNT1(bicolor_count, s, bicolor1, bicolor2); + } + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT1(count, s, temp_s); + OUT_FOM_COUNT1(fom_count, s, fom_mask, fom_mask_len); + } + else + { + OUT_COPY_COUNT1(count, s, temp_s); + } + } + else if ((bpp == 15) || (bpp == 16)) + { + mix = (bpp == 15) ? 0xBA1F : 0xFFFF; + out_count = end * 2; + line = in_data + width * start_line * 2; + + while (start_line >= 0 && out_count < 32768) + { + i = Stream_GetPosition(s) + count * 2; + + if (i - (color_count * 2) >= byte_limit && + i - (bicolor_count * 2) >= byte_limit && + i - (fill_count * 2) >= byte_limit && + i - (mix_count * 2) >= byte_limit && + i - (fom_count * 2) >= byte_limit) + { + break; + } + + out_count += end * 2; + + for (i = 0; i < end; i++) + { + /* read next pixel */ + IN_PIXEL16(line, i, 0, width, last_pixel, pixel); + IN_PIXEL16(last_line, i, 0, width, last_ypixel, ypixel); + + if (!TEST_FILL) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + } + + if (!TEST_MIX) + { + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + } + + if (!TEST_COLOR) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_COLOR_COUNT2(color_count, s, last_pixel); + RESET_COUNTS; + } + + color_count = 0; + } + + if (!TEST_BICOLOR) + { + if (bicolor_count > 3 && + bicolor_count >= fill_count && + bicolor_count >= color_count && + bicolor_count >= mix_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); + } + + RESET_COUNTS; + } + + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = 0; + } + + if (!TEST_FOM) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + if (TEST_FILL) + { + fill_count++; + } + + if (TEST_MIX) + { + mix_count++; + } + + if (TEST_COLOR) + { + color_count++; + } + + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + + fom_count++; + } + + Stream_Write_UINT16(temp_s, pixel); + count++; + last_pixel = pixel; + last_ypixel = ypixel; + } + + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + last_line = line; + line = line - width * 2; + start_line--; + lines_sent++; + } + + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + } + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + } + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_COLOR_COUNT2(color_count, s, last_pixel); + } + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); + } + + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); + } + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + } + else + { + OUT_COPY_COUNT2(count, s, temp_s); + } + } + else if (bpp == 24) + { + mix = 0xFFFFFF; + out_count = end * 3; + line = in_data + width * start_line * 4; + + while (start_line >= 0 && out_count < 32768) + { + i = Stream_GetPosition(s) + count * 3; + + if (i - (color_count * 3) >= byte_limit && + i - (bicolor_count * 3) >= byte_limit && + i - (fill_count * 3) >= byte_limit && + i - (mix_count * 3) >= byte_limit && + i - (fom_count * 3) >= byte_limit) + { + break; + } + + out_count += end * 3; + + for (i = 0; i < end; i++) + { + /* read next pixel */ + IN_PIXEL32(line, i, 0, width, last_pixel, pixel); + IN_PIXEL32(last_line, i, 0, width, last_ypixel, ypixel); + + if (!TEST_FILL) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FILL_COUNT3(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + } + + if (!TEST_MIX) + { + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_MIX_COUNT3(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + } + + if (!TEST_COLOR) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_COLOR_COUNT3(color_count, s, last_pixel); + RESET_COUNTS; + } + + color_count = 0; + } + + if (!TEST_BICOLOR) + { + if (bicolor_count > 3 && + bicolor_count >= fill_count && + bicolor_count >= color_count && + bicolor_count >= mix_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); + } + + RESET_COUNTS; + } + + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = 0; + } + + if (!TEST_FOM) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + if (TEST_FILL) + { + fill_count++; + } + + if (TEST_MIX) + { + mix_count++; + } + + if (TEST_COLOR) + { + color_count++; + } + + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + + fom_count++; + } + + Stream_Write_UINT8(temp_s, pixel & 0xff); + Stream_Write_UINT8(temp_s, (pixel >> 8) & 0xff); + Stream_Write_UINT8(temp_s, (pixel >> 16) & 0xff); + count++; + last_pixel = pixel; + last_ypixel = ypixel; + } + + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FILL_COUNT3(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_MIX_COUNT3(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + last_line = line; + line = line - width * 4; + start_line--; + lines_sent++; + } + + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + count -= fill_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FILL_COUNT3(fill_count, s); + } + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) + { + count -= mix_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_MIX_COUNT3(mix_count, s); + } + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) + { + count -= color_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_COLOR_COUNT3(color_count, s, last_pixel); + } + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) == 0) + { + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); + } + else + { + bicolor_count--; + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); + } + + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); + } + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) + { + count -= fom_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); + } + else + { + OUT_COPY_COUNT3(count, s, temp_s); + } + } + + return lines_sent; +} + +/** + * RDP6 Bitmap Test Case ([MS-RDPEGDI]) + */ + +const BYTE TEST_RDP6_COMPRESSED_BITMAP[220] = + "\x85\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x06\x8B\x99\xD6\x99" + "\xD6\x99\xD6\x10\x84\x08\x42\x08\x42\x10\x84\x99\xD6\x99\xD6\x99" + "\xD6\x99\xD6\x06\x84\x99\xD6\x99\xD6\x99\xD6\xFF\xFF\x16\x69\x99" + "\xD6\x06\x69\x99\xD6\x04\xCC\x89\x52\x03\x6E\xFF\xFF\x02\x6E\x08" + "\x42\x01\x70\x08\x42\x71\xFF\xFF\xCE\x18\xC6\x01\x81\x08\x42\xCE" + "\x66\x29\x02\xCD\x89\x52\x03\x88\x10\x84\x99\xD6\x99\xD6\x99\xD6" + "\x00\x00\x00\x00\x00\x00\x00\x00\xD8\x99\xD6\x03\xF8\x01\x00\x00" + "\x00\x00\xF0\x66\x99\xD6\x05\x6A\x99\xD6\x00\xC4\xCC\x89\x52\x03" + "\x6E\xFF\xFF\x02\x6E\x08\x42\x01\x70\x08\x42\x71\xFF\xFF\xCE\x18" + "\xC6\x01\x81\x08\x42\xCE\x66\x29\x02\xCD\x89\x52\x03\x00\x04\xD6" + "\x99\xD6\xC3\x80\x61\x00\xA5\x80\x40\xEC\x52\x00\x5A\x00\x2D\x00" + "\x24\x00\x12\x00\x24\x00\x12\x00\x5A\x00\x2D\x00\xA5\x80\x52\x00" + "\xC3\x80\x61\x00\x00\x00\x00\x00\xCC\x89\x52\x03\x6E\xFF\xFF\x02" + "\xCB\x18\xC6\x84\x08\x42\x08\x42\x08\x42\xFF\xFF"; + +const BYTE TEST_RDP6_UNCOMPRESSED_BITMAP[2048] = + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x08\x42" + "\x08\x42\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x08\x42" + "\x08\x42\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6" + "\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00" + "\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00" + "\x00\x00\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00" + "\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6" + "\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x00\x00\x00\x00\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\xFF\xFF" + "\xFF\xFF\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6" + "\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x99\xD6\x10\x84\x08\x42" + "\x08\x42\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84" + "\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x10\x84\x99\xD6\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" + "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42" + "\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\x08\x42\xFF\xFF"; diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index ba435a0c8..b869b028f 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -61,7 +61,7 @@ static void nsc_decode(NSC_CONTEXT* context) INT16 b_val; BYTE* bmpdata; - bmpdata = context->bmpdata; + bmpdata = context->BitmapData; rw = ROUND_UP_TO(context->width, 8); shift = context->nsc_stream.ColorLossLevel - 1; /* colorloss recovery + YCoCg shift */ @@ -69,17 +69,19 @@ static void nsc_decode(NSC_CONTEXT* context) { if (context->nsc_stream.ChromaSubSamplingLevel > 0) { - yplane = context->priv->plane_buf[0] + y * rw; /* Y */ - coplane = context->priv->plane_buf[1] + (y >> 1) * (rw >> 1); /* Co, supersampled */ - cgplane = context->priv->plane_buf[2] + (y >> 1) * (rw >> 1); /* Cg, supersampled */ + yplane = context->priv->PlaneBuffers[0] + y * rw; /* Y */ + coplane = context->priv->PlaneBuffers[1] + (y >> 1) * (rw >> 1); /* Co, supersampled */ + cgplane = context->priv->PlaneBuffers[2] + (y >> 1) * (rw >> 1); /* Cg, supersampled */ } else { - yplane = context->priv->plane_buf[0] + y * context->width; /* Y */ - coplane = context->priv->plane_buf[1] + y * context->width; /* Co */ - cgplane = context->priv->plane_buf[2] + y * context->width; /* Cg */ + yplane = context->priv->PlaneBuffers[0] + y * context->width; /* Y */ + coplane = context->priv->PlaneBuffers[1] + y * context->width; /* Co */ + cgplane = context->priv->PlaneBuffers[2] + y * context->width; /* Cg */ } - aplane = context->priv->plane_buf[3] + y * context->width; /* A */ + + aplane = context->priv->PlaneBuffers[3] + y * context->width; /* A */ + for (x = 0; x < context->width; x++) { y_val = (INT16) *yplane; @@ -100,13 +102,14 @@ static void nsc_decode(NSC_CONTEXT* context) } } -static void nsc_rle_decode(BYTE* in, BYTE* out, UINT32 origsz) +static void nsc_rle_decode(BYTE* in, BYTE* out, UINT32 originalSize) { UINT32 len; UINT32 left; BYTE value; - left = origsz; + left = originalSize; + while (left > 4) { value = *in++; @@ -119,6 +122,7 @@ static void nsc_rle_decode(BYTE* in, BYTE* out, UINT32 origsz) else if (value == *in) { in++; + if (*in < 0xFF) { len = (UINT32) *in++; @@ -130,7 +134,8 @@ static void nsc_rle_decode(BYTE* in, BYTE* out, UINT32 origsz) len = *((UINT32*) in); in += 4; } - memset(out, value, len); + + FillMemory(out, len, value); out += len; left -= len; } @@ -148,24 +153,24 @@ static void nsc_rle_decompress_data(NSC_CONTEXT* context) { UINT16 i; BYTE* rle; - UINT32 origsize; - UINT32 planesize; + UINT32 planeSize; + UINT32 originalSize; rle = context->nsc_stream.Planes; for (i = 0; i < 4; i++) { - origsize = context->OrgByteCount[i]; - planesize = context->nsc_stream.PlaneByteCount[i]; + originalSize = context->OrgByteCount[i]; + planeSize = context->nsc_stream.PlaneByteCount[i]; - if (planesize == 0) - memset(context->priv->plane_buf[i], 0xff, origsize); - else if (planesize < origsize) - nsc_rle_decode(rle, context->priv->plane_buf[i], origsize); + if (planeSize == 0) + FillMemory(context->priv->PlaneBuffers[i], originalSize, 0xFF); + else if (planeSize < originalSize) + nsc_rle_decode(rle, context->priv->PlaneBuffers[i], originalSize); else - memcpy(context->priv->plane_buf[i], rle, origsize); + CopyMemory(context->priv->PlaneBuffers[i], rle, originalSize); - rle += planesize; + rle += planeSize; } } @@ -192,31 +197,37 @@ static void nsc_context_initialize(NSC_CONTEXT* context, wStream* s) nsc_stream_initialize(context, s); length = context->width * context->height * 4; - if (context->bmpdata == NULL) + + if (!context->BitmapData) { - context->bmpdata = malloc(length + 16); - ZeroMemory(context->bmpdata, length + 16); - context->bmpdata_length = length; + context->BitmapData = malloc(length + 16); + ZeroMemory(context->BitmapData, length + 16); + context->BitmapDataLength = length; } - else if (length > context->bmpdata_length) + else if (length > context->BitmapDataLength) { - context->bmpdata = realloc(context->bmpdata, length + 16); - context->bmpdata_length = length; + context->BitmapData = realloc(context->BitmapData, length + 16); + context->BitmapDataLength = length; } tempWidth = ROUND_UP_TO(context->width, 8); tempHeight = ROUND_UP_TO(context->height, 2); + /* The maximum length a decoded plane can reach in all cases */ length = tempWidth * tempHeight; - if (length > context->priv->plane_buf_length) + + if (length > context->priv->PlaneBuffersLength) { for (i = 0; i < 4; i++) - context->priv->plane_buf[i] = (BYTE*) realloc(context->priv->plane_buf[i], length); - context->priv->plane_buf_length = length; + context->priv->PlaneBuffers[i] = (BYTE*) realloc(context->priv->PlaneBuffers[i], length); + + context->priv->PlaneBuffersLength = length; } for (i = 0; i < 4; i++) - context->OrgByteCount[i]=context->width * context->height; + { + context->OrgByteCount[i] = context->width * context->height; + } if (context->nsc_stream.ChromaSubSamplingLevel > 0) /* [MS-RDPNSC] 2.2 */ { @@ -238,20 +249,58 @@ static void nsc_profiler_print(NSC_CONTEXT* context) PROFILER_PRINT_FOOTER; } +NSC_CONTEXT* nsc_context_new(void) +{ + UINT8 i; + NSC_CONTEXT* context; + + context = (NSC_CONTEXT*) calloc(1, sizeof(NSC_CONTEXT)); + context->priv = (NSC_CONTEXT_PRIV*) calloc(1, sizeof(NSC_CONTEXT_PRIV)); + + for (i = 0; i < 5; ++i) + { + context->priv->PlaneBuffers[i] = NULL; + } + + context->BitmapData = NULL; + + context->decode = nsc_decode; + context->encode = nsc_encode; + + context->priv->PlanePool = BufferPool_New(TRUE, 0, 16); + + PROFILER_CREATE(context->priv->prof_nsc_rle_decompress_data, "nsc_rle_decompress_data"); + PROFILER_CREATE(context->priv->prof_nsc_decode, "nsc_decode"); + PROFILER_CREATE(context->priv->prof_nsc_rle_compress_data, "nsc_rle_compress_data"); + PROFILER_CREATE(context->priv->prof_nsc_encode, "nsc_encode"); + + /* Default encoding parameters */ + context->nsc_stream.ColorLossLevel = 3; + context->nsc_stream.ChromaSubSamplingLevel = 1; + + /* init optimized methods */ + NSC_INIT_SIMD(context); + + return context; +} + void nsc_context_free(NSC_CONTEXT* context) { int i; for (i = 0; i < 4; i++) { - if (context->priv->plane_buf[i]) + if (context->priv->PlaneBuffers[i]) { - free(context->priv->plane_buf[i]); - context->priv->plane_buf[i] = NULL; + free(context->priv->PlaneBuffers[i]); + context->priv->PlaneBuffers[i] = NULL; } } - if (context->bmpdata) - free(context->bmpdata); + + if (context->BitmapData) + free(context->BitmapData); + + BufferPool_Free(context->priv->PlanePool); nsc_profiler_print(context); PROFILER_FREE(context->priv->prof_nsc_rle_decompress_data); @@ -261,71 +310,44 @@ void nsc_context_free(NSC_CONTEXT* context) free(context->priv); free(context); - context = NULL; -} - -NSC_CONTEXT* nsc_context_new(void) -{ - NSC_CONTEXT* nsc_context; - UINT8 i; - - nsc_context = (NSC_CONTEXT*) calloc(1, sizeof(NSC_CONTEXT)); - nsc_context->priv = (NSC_CONTEXT_PRIV*) calloc(1, sizeof(NSC_CONTEXT_PRIV)); - for (i=0; i < 5; ++i) - { - nsc_context->priv->plane_buf[i] = NULL; - } - nsc_context->bmpdata = NULL; - - nsc_context->decode = nsc_decode; - nsc_context->encode = nsc_encode; - - PROFILER_CREATE(nsc_context->priv->prof_nsc_rle_decompress_data, "nsc_rle_decompress_data"); - PROFILER_CREATE(nsc_context->priv->prof_nsc_decode, "nsc_decode"); - PROFILER_CREATE(nsc_context->priv->prof_nsc_rle_compress_data, "nsc_rle_compress_data"); - PROFILER_CREATE(nsc_context->priv->prof_nsc_encode, "nsc_encode"); - - /* Default encoding parameters */ - nsc_context->nsc_stream.ColorLossLevel = 3; - nsc_context->nsc_stream.ChromaSubSamplingLevel = 1; - - /* init optimized methods */ - NSC_INIT_SIMD(nsc_context); - - return nsc_context; } void nsc_context_set_pixel_format(NSC_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format) { context->pixel_format = pixel_format; + switch (pixel_format) { case RDP_PIXEL_FORMAT_B8G8R8A8: case RDP_PIXEL_FORMAT_R8G8B8A8: context->bpp = 32; break; + case RDP_PIXEL_FORMAT_B8G8R8: case RDP_PIXEL_FORMAT_R8G8B8: context->bpp = 24; break; + case RDP_PIXEL_FORMAT_B5G6R5_LE: case RDP_PIXEL_FORMAT_R5G6B5_LE: context->bpp = 16; break; + case RDP_PIXEL_FORMAT_P4_PLANER: context->bpp = 4; break; + case RDP_PIXEL_FORMAT_P8: context->bpp = 8; break; + default: context->bpp = 0; break; } } -void nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, - UINT16 width, UINT16 height, BYTE* data, UINT32 length) +void nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT16 width, UINT16 height, BYTE* data, UINT32 length) { wStream* s; diff --git a/libfreerdp/codec/nsc_encode.c b/libfreerdp/codec/nsc_encode.c index 143e44dc5..627d032f4 100644 --- a/libfreerdp/codec/nsc_encode.c +++ b/libfreerdp/codec/nsc_encode.c @@ -24,10 +24,13 @@ #include #include #include + #ifdef HAVE_STDINT_H #include #endif +#include + #include #include "nsc_types.h" @@ -42,13 +45,16 @@ static void nsc_context_initialize_encode(NSC_CONTEXT* context) tempWidth = ROUND_UP_TO(context->width, 8); tempHeight = ROUND_UP_TO(context->height, 2); + /* The maximum length a decoded plane can reach in all cases */ length = tempWidth * tempHeight + 16; - if (length > context->priv->plane_buf_length) + + if (length > context->priv->PlaneBuffersLength) { for (i = 0; i < 5; i++) - context->priv->plane_buf[i] = (BYTE*) realloc(context->priv->plane_buf[i], length); - context->priv->plane_buf_length = length; + context->priv->PlaneBuffers[i] = (BYTE*) realloc(context->priv->PlaneBuffers[i], length); + + context->priv->PlaneBuffersLength = length; } if (context->nsc_stream.ChromaSubSamplingLevel > 0) @@ -67,7 +73,7 @@ static void nsc_context_initialize_encode(NSC_CONTEXT* context) } } -static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride) +static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* data, int scanline) { UINT16 x; UINT16 y; @@ -89,18 +95,19 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int r tempHeight = ROUND_UP_TO(context->height, 2); rw = (context->nsc_stream.ChromaSubSamplingLevel > 0 ? tempWidth : context->width); ccl = context->nsc_stream.ColorLossLevel; - yplane = context->priv->plane_buf[0]; - coplane = context->priv->plane_buf[1]; - cgplane = context->priv->plane_buf[2]; - aplane = context->priv->plane_buf[3]; + yplane = context->priv->PlaneBuffers[0]; + coplane = context->priv->PlaneBuffers[1]; + cgplane = context->priv->PlaneBuffers[2]; + aplane = context->priv->PlaneBuffers[3]; for (y = 0; y < context->height; y++) { - src = bmpdata + (context->height - 1 - y) * rowstride; - yplane = context->priv->plane_buf[0] + y * rw; - coplane = context->priv->plane_buf[1] + y * rw; - cgplane = context->priv->plane_buf[2] + y * rw; - aplane = context->priv->plane_buf[3] + y * context->width; + src = data + (context->height - 1 - y) * scanline; + yplane = context->priv->PlaneBuffers[0] + y * rw; + coplane = context->priv->PlaneBuffers[1] + y * rw; + cgplane = context->priv->PlaneBuffers[2] + y * rw; + aplane = context->priv->PlaneBuffers[3] + y * context->width; + for (x = 0; x < context->width; x++) { switch (context->pixel_format) @@ -111,24 +118,28 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int r r_val = *src++; a_val = *src++; break; + case RDP_PIXEL_FORMAT_R8G8B8A8: r_val = *src++; g_val = *src++; b_val = *src++; a_val = *src++; break; + case RDP_PIXEL_FORMAT_B8G8R8: b_val = *src++; g_val = *src++; r_val = *src++; a_val = 0xFF; break; + case RDP_PIXEL_FORMAT_R8G8B8: r_val = *src++; g_val = *src++; b_val = *src++; a_val = 0xFF; break; + case RDP_PIXEL_FORMAT_B5G6R5_LE: b_val = (INT16) (((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5)); g_val = (INT16) ((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)); @@ -136,6 +147,7 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int r a_val = 0xFF; src += 2; break; + case RDP_PIXEL_FORMAT_R5G6B5_LE: r_val = (INT16) (((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5)); g_val = (INT16) ((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)); @@ -143,6 +155,7 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int r a_val = 0xFF; src += 2; break; + case RDP_PIXEL_FORMAT_P4_PLANER: { int shift; @@ -162,6 +175,7 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int r } a_val = 0xFF; break; + case RDP_PIXEL_FORMAT_P8: { int idx = (*src) * 3; @@ -173,16 +187,20 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int r } a_val = 0xFF; break; + default: r_val = g_val = b_val = a_val = 0; break; } + *yplane++ = (BYTE) ((r_val >> 2) + (g_val >> 1) + (b_val >> 2)); + /* Perform color loss reduction here */ *coplane++ = (BYTE) ((r_val - b_val) >> ccl); *cgplane++ = (BYTE) ((-(r_val >> 1) + g_val - (b_val >> 1)) >> ccl); *aplane++ = a_val; } + if (context->nsc_stream.ChromaSubSamplingLevel > 0 && (x % 2) == 1) { *yplane = *(yplane - 1); @@ -190,11 +208,12 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int r *cgplane = *(cgplane - 1); } } + if (context->nsc_stream.ChromaSubSamplingLevel > 0 && (y % 2) == 1) { - memcpy(yplane + rw, yplane, rw); - memcpy(coplane + rw, coplane, rw); - memcpy(cgplane + rw, cgplane, rw); + CopyMemory(yplane + rw, yplane, rw); + CopyMemory(coplane + rw, coplane, rw); + CopyMemory(cgplane + rw, cgplane, rw); } } @@ -216,12 +235,13 @@ static void nsc_encode_subsampling(NSC_CONTEXT* context) for (y = 0; y < tempHeight >> 1; y++) { - co_dst = context->priv->plane_buf[1] + y * (tempWidth >> 1); - cg_dst = context->priv->plane_buf[2] + y * (tempWidth >> 1); - co_src0 = (INT8*) context->priv->plane_buf[1] + (y << 1) * tempWidth; + co_dst = context->priv->PlaneBuffers[1] + y * (tempWidth >> 1); + cg_dst = context->priv->PlaneBuffers[2] + y * (tempWidth >> 1); + co_src0 = (INT8*) context->priv->PlaneBuffers[1] + (y << 1) * tempWidth; co_src1 = co_src0 + tempWidth; - cg_src0 = (INT8*) context->priv->plane_buf[2] + (y << 1) * tempWidth; + cg_src0 = (INT8*) context->priv->PlaneBuffers[2] + (y << 1) * tempWidth; cg_src1 = cg_src0 + tempWidth; + for (x = 0; x < tempWidth >> 1; x++) { *co_dst++ = (BYTE) (((INT16) *co_src0 + (INT16) *(co_src0 + 1) + @@ -239,24 +259,25 @@ static void nsc_encode_subsampling(NSC_CONTEXT* context) void nsc_encode(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride) { nsc_encode_argb_to_aycocg(context, bmpdata, rowstride); + if (context->nsc_stream.ChromaSubSamplingLevel > 0) { nsc_encode_subsampling(context); } } -static UINT32 nsc_rle_encode(BYTE* in, BYTE* out, UINT32 origsz) +static UINT32 nsc_rle_encode(BYTE* in, BYTE* out, UINT32 originalSize) { UINT32 left; UINT32 runlength = 1; - UINT32 planesize = 0; + UINT32 planeSize = 0; - left = origsz; + left = originalSize; /** * We quit the loop if the running compressed size is larger than the original. * In such cases data will be sent uncompressed. */ - while (left > 4 && planesize < origsz - 4) + while (left > 4 && planeSize < originalSize - 4) { if (left > 5 && *in == *(in + 1)) { @@ -265,7 +286,7 @@ static UINT32 nsc_rle_encode(BYTE* in, BYTE* out, UINT32 origsz) else if (runlength == 1) { *out++ = *in; - planesize++; + planeSize++; } else if (runlength < 256) { @@ -273,7 +294,7 @@ static UINT32 nsc_rle_encode(BYTE* in, BYTE* out, UINT32 origsz) *out++ = *in; *out++ = runlength - 2; runlength = 1; - planesize += 3; + planeSize += 3; } else { @@ -285,52 +306,213 @@ static UINT32 nsc_rle_encode(BYTE* in, BYTE* out, UINT32 origsz) *out++ = (runlength & 0x00FF0000) >> 16; *out++ = (runlength & 0xFF000000) >> 24; runlength = 1; - planesize += 7; + planeSize += 7; } in++; left--; } - if (planesize < origsz - 4) - { - memcpy(out, in, 4); - } - planesize += 4; - return planesize; + if (planeSize < originalSize - 4) + CopyMemory(out, in, 4); + + planeSize += 4; + + return planeSize; } static void nsc_rle_compress_data(NSC_CONTEXT* context) { UINT16 i; - BYTE* rle; - UINT32 origsize; - UINT32 planesize; - - rle = context->nsc_stream.Planes; + UINT32 planeSize; + UINT32 originalSize; for (i = 0; i < 4; i++) { - origsize = context->OrgByteCount[i]; - if (origsize == 0) + originalSize = context->OrgByteCount[i]; + + if (originalSize == 0) { - planesize = 0; + planeSize = 0; } else { - planesize = nsc_rle_encode(context->priv->plane_buf[i], - context->priv->plane_buf[4], origsize); - if (planesize < origsize) - memcpy(context->priv->plane_buf[i], context->priv->plane_buf[4], planesize); + planeSize = nsc_rle_encode(context->priv->PlaneBuffers[i], context->priv->PlaneBuffers[4], originalSize); + + if (planeSize < originalSize) + CopyMemory(context->priv->PlaneBuffers[i], context->priv->PlaneBuffers[4], planeSize); else - planesize = origsize; + planeSize = originalSize; } - context->nsc_stream.PlaneByteCount[i] = planesize; + context->nsc_stream.PlaneByteCount[i] = planeSize; } } -void nsc_compose_message(NSC_CONTEXT* context, wStream* s, - BYTE* bmpdata, int width, int height, int rowstride) +UINT32 nsc_compute_byte_count(NSC_CONTEXT* context, UINT32* ByteCount, UINT32 width, UINT32 height) +{ + UINT32 tempWidth; + UINT32 tempHeight; + UINT32 maxPlaneSize; + + tempWidth = ROUND_UP_TO(width, 8); + tempHeight = ROUND_UP_TO(height, 2); + + maxPlaneSize = tempWidth * tempHeight + 16; + + if (context->nsc_stream.ChromaSubSamplingLevel > 0) + { + ByteCount[0] = tempWidth * height; + ByteCount[1] = tempWidth * tempHeight / 4; + ByteCount[2] = tempWidth * tempHeight / 4; + ByteCount[3] = width * height; + } + else + { + ByteCount[0] = width * height; + ByteCount[1] = width * height; + ByteCount[2] = width * height; + ByteCount[3] = width * height; + } + + return maxPlaneSize; +} + +NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y, + int width, int height, int scanline, int* numMessages, int maxDataSize) +{ + int i, j, k; + int dataOffset; + int rows, cols; + int BytesPerPixel; + int MaxRegionWidth; + int MaxRegionHeight; + UINT32 ByteCount[4]; + UINT32 MaxPlaneSize; + UINT32 MaxMessageSize; + NSC_MESSAGE* messages; + + k = 0; + MaxRegionWidth = 64 * 4; + MaxRegionHeight = 64 * 2; + BytesPerPixel = (context->bpp / 8); + + rows = (width + (MaxRegionWidth - (width % MaxRegionWidth))) / MaxRegionWidth; + cols = (height + (MaxRegionHeight - (height % MaxRegionHeight))) / MaxRegionHeight; + *numMessages = rows * cols; + + MaxPlaneSize = nsc_compute_byte_count(context, (UINT32*) ByteCount, width, height); + MaxMessageSize = ByteCount[0] + ByteCount[1] + ByteCount[2] + ByteCount[3] + 20; + + maxDataSize -= 1024; /* reserve enough space for headers */ + + messages = (NSC_MESSAGE*) malloc(sizeof(NSC_MESSAGE) * (*numMessages)); + ZeroMemory(messages, sizeof(sizeof(NSC_MESSAGE) * (*numMessages))); + + for (i = 0; i < rows; i++) + { + for (j = 0; j < cols; j++) + { + messages[k].x = x + (i * MaxRegionWidth); + messages[k].y = y + (j * MaxRegionHeight); + messages[k].width = (i < (rows - 1)) ? MaxRegionWidth : width - (i * MaxRegionWidth); + messages[k].height = (j < (cols - 1)) ? MaxRegionHeight : height - (j * MaxRegionHeight); + messages[k].data = data; + messages[k].scanline = scanline; + + messages[k].MaxPlaneSize = nsc_compute_byte_count(context, + (UINT32*) messages[k].OrgByteCount, messages[k].width, messages[k].height); + + k++; + } + } + + *numMessages = k; + + for (i = 0; i < *numMessages; i++) + { + messages[i].PlaneBuffers[0] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize); + messages[i].PlaneBuffers[1] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize); + messages[i].PlaneBuffers[2] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize); + messages[i].PlaneBuffers[3] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize); + messages[i].PlaneBuffers[4] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize); + } + + for (i = 0; i < *numMessages; i++) + { + context->width = messages[i].width; + context->height = messages[i].height; + context->OrgByteCount[0] = messages[i].OrgByteCount[0]; + context->OrgByteCount[1] = messages[i].OrgByteCount[1]; + context->OrgByteCount[2] = messages[i].OrgByteCount[2]; + context->OrgByteCount[3] = messages[i].OrgByteCount[3]; + context->priv->PlaneBuffersLength = messages[i].MaxPlaneSize; + context->priv->PlaneBuffers[0] = messages[i].PlaneBuffers[0]; + context->priv->PlaneBuffers[1] = messages[i].PlaneBuffers[1]; + context->priv->PlaneBuffers[2] = messages[i].PlaneBuffers[2]; + context->priv->PlaneBuffers[3] = messages[i].PlaneBuffers[3]; + context->priv->PlaneBuffers[4] = messages[i].PlaneBuffers[4]; + + dataOffset = (messages[i].y * messages[i].scanline) + (messages[i].x * BytesPerPixel); + + PROFILER_ENTER(context->priv->prof_nsc_encode); + context->encode(context, &data[dataOffset], scanline); + PROFILER_EXIT(context->priv->prof_nsc_encode); + + PROFILER_ENTER(context->priv->prof_nsc_rle_compress_data); + nsc_rle_compress_data(context); + PROFILER_EXIT(context->priv->prof_nsc_rle_compress_data); + + messages[i].PlaneByteCount[0] = context->nsc_stream.PlaneByteCount[0]; + messages[i].PlaneByteCount[1] = context->nsc_stream.PlaneByteCount[1]; + messages[i].PlaneByteCount[2] = context->nsc_stream.PlaneByteCount[2]; + messages[i].PlaneByteCount[3] = context->nsc_stream.PlaneByteCount[3]; + } + + context->priv->PlaneBuffers[0] = NULL; + context->priv->PlaneBuffers[1] = NULL; + context->priv->PlaneBuffers[2] = NULL; + context->priv->PlaneBuffers[3] = NULL; + context->priv->PlaneBuffers[4] = NULL; + + return messages; +} + +int nsc_write_message(NSC_CONTEXT* context, wStream* s, NSC_MESSAGE* message) +{ + int i; + + Stream_EnsureRemainingCapacity(s, 20); + Stream_Write_UINT32(s, message->PlaneByteCount[0]); /* LumaPlaneByteCount (4 bytes) */ + Stream_Write_UINT32(s, message->PlaneByteCount[1]); /* OrangeChromaPlaneByteCount (4 bytes) */ + Stream_Write_UINT32(s, message->PlaneByteCount[2]); /* GreenChromaPlaneByteCount (4 bytes) */ + Stream_Write_UINT32(s, message->PlaneByteCount[3]); /* AlphaPlaneByteCount (4 bytes) */ + Stream_Write_UINT8(s, context->nsc_stream.ColorLossLevel); /* ColorLossLevel (1 byte) */ + Stream_Write_UINT8(s, context->nsc_stream.ChromaSubSamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ + Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */ + + for (i = 0; i < 4; i++) + { + if (message->PlaneByteCount[i] > 0) + { + Stream_EnsureRemainingCapacity(s, (int) message->PlaneByteCount[i]); + Stream_Write(s, message->PlaneBuffers[i], message->PlaneByteCount[i]); + } + } + + return 0; +} + +int nsc_message_free(NSC_CONTEXT* context, NSC_MESSAGE* message) +{ + BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[0]); + BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[1]); + BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[2]); + BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[3]); + BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[4]); + return 0; +} + +void nsc_compose_message(NSC_CONTEXT* context, wStream* s, BYTE* data, int width, int height, int scanline) { int i; @@ -340,7 +522,7 @@ void nsc_compose_message(NSC_CONTEXT* context, wStream* s, /* ARGB to AYCoCg conversion, chroma subsampling and colorloss reduction */ PROFILER_ENTER(context->priv->prof_nsc_encode); - context->encode(context, bmpdata, rowstride); + context->encode(context, data, scanline); PROFILER_EXIT(context->priv->prof_nsc_encode); /* RLE encode */ @@ -363,7 +545,7 @@ void nsc_compose_message(NSC_CONTEXT* context, wStream* s, if (context->nsc_stream.PlaneByteCount[i] > 0) { Stream_EnsureRemainingCapacity(s, (int) context->nsc_stream.PlaneByteCount[i]); - Stream_Write(s, context->priv->plane_buf[i], context->nsc_stream.PlaneByteCount[i]); + Stream_Write(s, context->priv->PlaneBuffers[i], context->nsc_stream.PlaneByteCount[i]); } } } diff --git a/libfreerdp/codec/nsc_sse2.c b/libfreerdp/codec/nsc_sse2.c index f1a033fc4..f4f1eb1bf 100644 --- a/libfreerdp/codec/nsc_sse2.c +++ b/libfreerdp/codec/nsc_sse2.c @@ -28,10 +28,12 @@ #include #include +#include + #include "nsc_types.h" #include "nsc_sse2.h" -static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride) +static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* data, int scanline) { UINT16 x; UINT16 y; @@ -56,18 +58,19 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, tempHeight = ROUND_UP_TO(context->height, 2); rw = (context->nsc_stream.ChromaSubSamplingLevel > 0 ? tempWidth : context->width); ccl = context->nsc_stream.ColorLossLevel; - yplane = context->priv->plane_buf[0]; - coplane = context->priv->plane_buf[1]; - cgplane = context->priv->plane_buf[2]; - aplane = context->priv->plane_buf[3]; + yplane = context->priv->PlaneBuffers[0]; + coplane = context->priv->PlaneBuffers[1]; + cgplane = context->priv->PlaneBuffers[2]; + aplane = context->priv->PlaneBuffers[3]; for (y = 0; y < context->height; y++) { - src = bmpdata + (context->height - 1 - y) * rowstride; - yplane = context->priv->plane_buf[0] + y * rw; - coplane = context->priv->plane_buf[1] + y * rw; - cgplane = context->priv->plane_buf[2] + y * rw; - aplane = context->priv->plane_buf[3] + y * context->width; + src = data + (context->height - 1 - y) * scanline; + yplane = context->priv->PlaneBuffers[0] + y * rw; + coplane = context->priv->PlaneBuffers[1] + y * rw; + cgplane = context->priv->PlaneBuffers[2] + y * rw; + aplane = context->priv->PlaneBuffers[3] + y * context->width; + for (x = 0; x < context->width; x += 8) { switch (context->pixel_format) @@ -79,6 +82,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, a_val = _mm_set_epi16(*(src + 31), *(src + 27), *(src + 23), *(src + 19), *(src + 15), *(src + 11), *(src + 7), *(src + 3)); src += 32; break; + case RDP_PIXEL_FORMAT_R8G8B8A8: r_val = _mm_set_epi16(*(src + 28), *(src + 24), *(src + 20), *(src + 16), *(src + 12), *(src + 8), *(src + 4), *src); g_val = _mm_set_epi16(*(src + 29), *(src + 25), *(src + 21), *(src + 17), *(src + 13), *(src + 9), *(src + 5), *(src + 1)); @@ -86,6 +90,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, a_val = _mm_set_epi16(*(src + 31), *(src + 27), *(src + 23), *(src + 19), *(src + 15), *(src + 11), *(src + 7), *(src + 3)); src += 32; break; + case RDP_PIXEL_FORMAT_B8G8R8: b_val = _mm_set_epi16(*(src + 21), *(src + 18), *(src + 15), *(src + 12), *(src + 9), *(src + 6), *(src + 3), *src); g_val = _mm_set_epi16(*(src + 22), *(src + 19), *(src + 16), *(src + 13), *(src + 10), *(src + 7), *(src + 4), *(src + 1)); @@ -93,6 +98,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, a_val = _mm_set1_epi16(0xFF); src += 24; break; + case RDP_PIXEL_FORMAT_R8G8B8: r_val = _mm_set_epi16(*(src + 21), *(src + 18), *(src + 15), *(src + 12), *(src + 9), *(src + 6), *(src + 3), *src); g_val = _mm_set_epi16(*(src + 22), *(src + 19), *(src + 16), *(src + 13), *(src + 10), *(src + 7), *(src + 4), *(src + 1)); @@ -100,6 +106,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, a_val = _mm_set1_epi16(0xFF); src += 24; break; + case RDP_PIXEL_FORMAT_B5G6R5_LE: b_val = _mm_set_epi16( (((*(src + 15)) & 0xF8) | ((*(src + 15)) >> 5)), @@ -131,6 +138,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, a_val = _mm_set1_epi16(0xFF); src += 16; break; + case RDP_PIXEL_FORMAT_R5G6B5_LE: r_val = _mm_set_epi16( (((*(src + 15)) & 0xF8) | ((*(src + 15)) >> 5)), @@ -162,6 +170,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, a_val = _mm_set1_epi16(0xFF); src += 16; break; + case RDP_PIXEL_FORMAT_P4_PLANER: { int shift; @@ -206,6 +215,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, } a_val = _mm_set1_epi16(0xFF); break; + case RDP_PIXEL_FORMAT_P8: { r_val = _mm_set_epi16( @@ -239,6 +249,7 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, } a_val = _mm_set1_epi16(0xFF); break; + default: r_val = g_val = b_val = a_val = _mm_set1_epi16(0); break; @@ -266,18 +277,20 @@ static void nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, BYTE* bmpdata, cgplane += 8; aplane += 8; } + if (context->nsc_stream.ChromaSubSamplingLevel > 0 && (context->width % 2) == 1) { - context->priv->plane_buf[0][y * rw + context->width] = context->priv->plane_buf[0][y * rw + context->width - 1]; - context->priv->plane_buf[1][y * rw + context->width] = context->priv->plane_buf[1][y * rw + context->width - 1]; - context->priv->plane_buf[2][y * rw + context->width] = context->priv->plane_buf[2][y * rw + context->width - 1]; + context->priv->PlaneBuffers[0][y * rw + context->width] = context->priv->PlaneBuffers[0][y * rw + context->width - 1]; + context->priv->PlaneBuffers[1][y * rw + context->width] = context->priv->PlaneBuffers[1][y * rw + context->width - 1]; + context->priv->PlaneBuffers[2][y * rw + context->width] = context->priv->PlaneBuffers[2][y * rw + context->width - 1]; } } + if (context->nsc_stream.ChromaSubSamplingLevel > 0 && (y % 2) == 1) { - memcpy(yplane + rw, yplane, rw); - memcpy(coplane + rw, coplane, rw); - memcpy(cgplane + rw, cgplane, rw); + CopyMemory(yplane + rw, yplane, rw); + CopyMemory(coplane + rw, coplane, rw); + CopyMemory(cgplane + rw, cgplane, rw); } } @@ -302,12 +315,13 @@ static void nsc_encode_subsampling_sse2(NSC_CONTEXT* context) for (y = 0; y < tempHeight >> 1; y++) { - co_dst = context->priv->plane_buf[1] + y * (tempWidth >> 1); - cg_dst = context->priv->plane_buf[2] + y * (tempWidth >> 1); - co_src0 = (INT8*) context->priv->plane_buf[1] + (y << 1) * tempWidth; + co_dst = context->priv->PlaneBuffers[1] + y * (tempWidth >> 1); + cg_dst = context->priv->PlaneBuffers[2] + y * (tempWidth >> 1); + co_src0 = (INT8*) context->priv->PlaneBuffers[1] + (y << 1) * tempWidth; co_src1 = co_src0 + tempWidth; - cg_src0 = (INT8*) context->priv->plane_buf[2] + (y << 1) * tempWidth; + cg_src0 = (INT8*) context->priv->PlaneBuffers[2] + (y << 1) * tempWidth; cg_src1 = cg_src0 + tempWidth; + for (x = 0; x < tempWidth >> 1; x += 8) { t = _mm_loadu_si128((__m128i*) co_src0); @@ -333,9 +347,10 @@ static void nsc_encode_subsampling_sse2(NSC_CONTEXT* context) } } -static void nsc_encode_sse2(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride) +static void nsc_encode_sse2(NSC_CONTEXT* context, BYTE* data, int scanline) { - nsc_encode_argb_to_aycocg_sse2(context, bmpdata, rowstride); + nsc_encode_argb_to_aycocg_sse2(context, data, scanline); + if (context->nsc_stream.ChromaSubSamplingLevel > 0) { nsc_encode_subsampling_sse2(context); diff --git a/libfreerdp/codec/nsc_types.h b/libfreerdp/codec/nsc_types.h index 060b89daa..0964167a2 100644 --- a/libfreerdp/codec/nsc_types.h +++ b/libfreerdp/codec/nsc_types.h @@ -25,6 +25,9 @@ #include "config.h" #endif +#include +#include + #include #include @@ -33,8 +36,10 @@ struct _NSC_CONTEXT_PRIV { - BYTE* plane_buf[5]; /* Decompressed Plane Buffers in the respective order */ - UINT32 plane_buf_length; /* Lengths of each plane buffer */ + wBufferPool* PlanePool; + + BYTE* PlaneBuffers[5]; /* Decompressed Plane Buffers in the respective order */ + UINT32 PlaneBuffersLength; /* Lengths of each plane buffer */ /* profilers */ PROFILER_DEFINE(prof_nsc_rle_decompress_data); diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index afd9e5ecc..5d6bbe7a1 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -45,6 +45,7 @@ #include "rfx_encode.h" #include "rfx_quantization.h" #include "rfx_dwt.h" +#include "rfx_rlgr.h" #include "rfx_sse2.h" #include "rfx_neon.h" @@ -137,6 +138,46 @@ static void rfx_profiler_print(RFX_CONTEXT* context) PROFILER_PRINT_FOOTER; } +void rfx_tile_init(RFX_TILE* tile) +{ + if (tile) + { + tile->x = 0; + tile->y = 0; + tile->YLen = 0; + tile->YData = NULL; + tile->CbLen = 0; + tile->CbData = NULL; + tile->CrLen = 0; + tile->CrData = NULL; + } +} + +RFX_TILE* rfx_tile_new() +{ + RFX_TILE* tile = NULL; + + tile = (RFX_TILE*) malloc(sizeof(RFX_TILE)); + + if (tile) + { + ZeroMemory(tile, sizeof(RFX_TILE)); + + tile->data = (BYTE*) malloc(4096 * 4); /* 64x64 * 4 */ + } + + return tile; +} + +void rfx_tile_free(RFX_TILE* tile) +{ + if (tile) + { + free(tile->data); + free(tile); + } +} + RFX_CONTEXT* rfx_context_new(void) { HKEY hKey; @@ -153,14 +194,16 @@ RFX_CONTEXT* rfx_context_new(void) context->priv = (RFX_CONTEXT_PRIV*) malloc(sizeof(RFX_CONTEXT_PRIV)); ZeroMemory(context->priv, sizeof(RFX_CONTEXT_PRIV)); - context->priv->TilePool = Queue_New(TRUE, -1, -1); - context->priv->TileQueue = Queue_New(TRUE, -1, -1); + context->priv->TilePool = ObjectPool_New(TRUE); + ObjectPool_Object(context->priv->TilePool)->fnObjectNew = (OBJECT_NEW_FN) rfx_tile_new; + ObjectPool_Object(context->priv->TilePool)->fnObjectInit = (OBJECT_INIT_FN) rfx_tile_init; + ObjectPool_Object(context->priv->TilePool)->fnObjectFree = (OBJECT_FREE_FN) rfx_tile_free; /* * align buffers to 16 byte boundary (needed for SSE/NEON instructions) * - * y_r_buffer, cb_g_buffer, cr_b_buffer: 64 * 64 * 4 = 16384 (0x4000) - * dwt_buffer: 32 * 32 * 2 * 2 * 4 = 16384, maximum sub-band width is 32 + * y_r_buffer, cb_g_buffer, cr_b_buffer: 64 * 64 * sizeof(INT16) = 8192 (0x2000) + * dwt_buffer: 32 * 32 * 2 * 2 * sizeof(INT16) = 8192, maximum sub-band width is 32 * * Additionally we add 32 bytes (16 in front and 16 at the back of the buffer) * in order to allow optimized functions (SEE, NEON) to read from positions @@ -168,7 +211,7 @@ RFX_CONTEXT* rfx_context_new(void) * performed at the BufferPool_Take function calls in rfx_encode/decode.c. */ - context->priv->BufferPool = BufferPool_New(TRUE, 16384 + 32, 16); + context->priv->BufferPool = BufferPool_New(TRUE, 8192 + 32, 16); #ifdef _WIN32 { @@ -196,6 +239,8 @@ RFX_CONTEXT* rfx_context_new(void) if (status == ERROR_SUCCESS) { + dwSize = sizeof(dwValue); + if (RegQueryValueEx(hKey, _T("UseThreads"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS) context->priv->UseThreads = dwValue ? 1 : 0; @@ -237,9 +282,13 @@ RFX_CONTEXT* rfx_context_new(void) context->quantization_encode = rfx_quantization_encode; context->dwt_2d_decode = rfx_dwt_2d_decode; context->dwt_2d_encode = rfx_dwt_2d_encode; + context->rlgr_decode = rfx_rlgr_decode; + context->rlgr_encode = rfx_rlgr_encode; RFX_INIT_SIMD(context); + context->state = RFX_STATE_SEND_HEADERS; + return context; } @@ -247,8 +296,7 @@ void rfx_context_free(RFX_CONTEXT* context) { free(context->quants); - Queue_Free(context->priv->TilePool); - Queue_Free(context->priv->TileQueue); + ObjectPool_Free(context->priv->TilePool); rfx_profiler_print(context); rfx_profiler_free(context); @@ -257,6 +305,9 @@ void rfx_context_free(RFX_CONTEXT* context) { CloseThreadpool(context->priv->ThreadPool); DestroyThreadpoolEnvironment(&context->priv->ThreadPoolEnv); +#ifdef WITH_PROFILER + fprintf(stderr, "\nWARNING: Profiling results probably unusable with multithreaded RemoteFX codec!\n"); +#endif } BufferPool_Free(context->priv->BufferPool); @@ -297,32 +348,8 @@ void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_f void rfx_context_reset(RFX_CONTEXT* context) { - context->header_processed = FALSE; - context->frame_idx = 0; -} - -RFX_TILE* rfx_tile_pool_take(RFX_CONTEXT* context) -{ - RFX_TILE* tile = NULL; - - if (WaitForSingleObject(Queue_Event(context->priv->TilePool), 0) == WAIT_OBJECT_0) - tile = Queue_Dequeue(context->priv->TilePool); - - if (!tile) - { - tile = (RFX_TILE*) malloc(sizeof(RFX_TILE)); - - tile->x = tile->y = 0; - tile->data = (BYTE*) malloc(4096 * 4); /* 64x64 * 4 */ - } - - return tile; -} - -int rfx_tile_pool_return(RFX_CONTEXT* context, RFX_TILE* tile) -{ - Queue_Enqueue(context->priv->TilePool, tile); - return 0; + context->state = RFX_STATE_SEND_HEADERS; + context->frameIdx = 0; } static BOOL rfx_process_message_sync(RFX_CONTEXT* context, wStream* s) @@ -505,27 +532,27 @@ static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* messag } Stream_Seek_UINT8(s); /* regionFlags (1 byte) */ - Stream_Read_UINT16(s, message->num_rects); /* numRects (2 bytes) */ + Stream_Read_UINT16(s, message->numRects); /* numRects (2 bytes) */ - if (message->num_rects < 1) + if (message->numRects < 1) { DEBUG_WARN("no rects."); return TRUE; } - if (Stream_GetRemainingLength(s) < 8 * message->num_rects) + if (Stream_GetRemainingLength(s) < 8 * message->numRects) { - DEBUG_WARN("RfxMessageRegion packet too small for num_rects=%d", message->num_rects); + DEBUG_WARN("RfxMessageRegion packet too small for num_rects=%d", message->numRects); return FALSE; } - if (message->rects != NULL) - message->rects = (RFX_RECT*) realloc(message->rects, message->num_rects * sizeof(RFX_RECT)); + if (message->rects) + message->rects = (RFX_RECT*) realloc(message->rects, message->numRects * sizeof(RFX_RECT)); else - message->rects = (RFX_RECT*) malloc(message->num_rects * sizeof(RFX_RECT)); + message->rects = (RFX_RECT*) malloc(message->numRects * sizeof(RFX_RECT)); /* rects */ - for (i = 0; i < message->num_rects; i++) + for (i = 0; i < message->numRects; i++) { /* RFX_RECT */ Stream_Read_UINT16(s, message->rects[i].x); /* x (2 bytes) */ @@ -539,55 +566,17 @@ static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* messag return TRUE; } -static BOOL rfx_process_message_tile(RFX_CONTEXT* context, RFX_TILE* tile, wStream* s) +struct _RFX_TILE_PROCESS_WORK_PARAM { - BYTE quantIdxY; - BYTE quantIdxCb; - BYTE quantIdxCr; - UINT16 xIdx, yIdx; - UINT16 YLen, CbLen, CrLen; - - if (Stream_GetRemainingLength(s) < 13) - { - DEBUG_WARN("RfxMessageTile packet too small"); - return FALSE; - } - - /* RFX_TILE */ - Stream_Read_UINT8(s, quantIdxY); /* quantIdxY (1 byte) */ - Stream_Read_UINT8(s, quantIdxCb); /* quantIdxCb (1 byte) */ - Stream_Read_UINT8(s, quantIdxCr); /* quantIdxCr (1 byte) */ - Stream_Read_UINT16(s, xIdx); /* xIdx (2 bytes) */ - Stream_Read_UINT16(s, yIdx); /* yIdx (2 bytes) */ - Stream_Read_UINT16(s, YLen); /* YLen (2 bytes) */ - Stream_Read_UINT16(s, CbLen); /* CbLen (2 bytes) */ - Stream_Read_UINT16(s, CrLen); /* CrLen (2 bytes) */ - - DEBUG_RFX("quantIdxY:%d quantIdxCb:%d quantIdxCr:%d xIdx:%d yIdx:%d YLen:%d CbLen:%d CrLen:%d", - quantIdxY, quantIdxCb, quantIdxCr, xIdx, yIdx, YLen, CbLen, CrLen); - - tile->x = xIdx * 64; - tile->y = yIdx * 64; - - return rfx_decode_rgb(context, s, - YLen, context->quants + (quantIdxY * 10), - CbLen, context->quants + (quantIdxCb * 10), - CrLen, context->quants + (quantIdxCr * 10), - tile->data, 64 * 4); -} - -struct _RFX_TILE_WORK_PARAM -{ - wStream s; RFX_TILE* tile; RFX_CONTEXT* context; }; -typedef struct _RFX_TILE_WORK_PARAM RFX_TILE_WORK_PARAM; +typedef struct _RFX_TILE_PROCESS_WORK_PARAM RFX_TILE_PROCESS_WORK_PARAM; void CALLBACK rfx_process_message_tile_work_callback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work) { - RFX_TILE_WORK_PARAM* param = (RFX_TILE_WORK_PARAM*) context; - rfx_process_message_tile(param->context, param->tile, &(param->s)); + RFX_TILE_PROCESS_WORK_PARAM* param = (RFX_TILE_PROCESS_WORK_PARAM*) context; + rfx_decode_rgb(param->context, param->tile, param->tile->data, 64 * 4); } static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s) @@ -595,13 +584,14 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa int i; int pos; BYTE quant; + RFX_TILE* tile; UINT32* quants; UINT16 subtype; UINT32 blockLen; UINT32 blockType; UINT32 tilesDataSize; PTP_WORK* work_objects = NULL; - RFX_TILE_WORK_PARAM* params = NULL; + RFX_TILE_PROCESS_WORK_PARAM* params = NULL; if (Stream_GetRemainingLength(s) < 14) { @@ -620,18 +610,18 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa Stream_Seek_UINT16(s); /* idx (2 bytes), must be set to 0x0000 */ Stream_Seek_UINT16(s); /* properties (2 bytes) */ - Stream_Read_UINT8(s, context->num_quants); /* numQuant (1 byte) */ + Stream_Read_UINT8(s, context->numQuant); /* numQuant (1 byte) */ Stream_Seek_UINT8(s); /* tileSize (1 byte), must be set to 0x40 */ - if (context->num_quants < 1) + if (context->numQuant < 1) { DEBUG_WARN("no quantization value."); return TRUE; } - Stream_Read_UINT16(s, message->num_tiles); /* numTiles (2 bytes) */ + Stream_Read_UINT16(s, message->numTiles); /* numTiles (2 bytes) */ - if (message->num_tiles < 1) + if (message->numTiles < 1) { DEBUG_WARN("no tiles."); return TRUE; @@ -640,19 +630,19 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa Stream_Read_UINT32(s, tilesDataSize); /* tilesDataSize (4 bytes) */ if (context->quants != NULL) - context->quants = (UINT32*) realloc((void*) context->quants, context->num_quants * 10 * sizeof(UINT32)); + context->quants = (UINT32*) realloc((void*) context->quants, context->numQuant * 10 * sizeof(UINT32)); else - context->quants = (UINT32*) malloc(context->num_quants * 10 * sizeof(UINT32)); + context->quants = (UINT32*) malloc(context->numQuant * 10 * sizeof(UINT32)); quants = context->quants; /* quantVals */ - if (Stream_GetRemainingLength(s) < context->num_quants * 5) + if (Stream_GetRemainingLength(s) < context->numQuant * 5) { - DEBUG_WARN("RfxMessageTileSet packet too small for num_quants=%d", context->num_quants); + DEBUG_WARN("RfxMessageTileSet packet too small for num_quants=%d", context->numQuant); return FALSE; } - for (i = 0; i < context->num_quants; i++) + for (i = 0; i < context->numQuant; i++) { /* RFX_CODEC_QUANT */ Stream_Read_UINT8(s, quant); @@ -679,22 +669,24 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa context->quants[i * 10 + 8], context->quants[i * 10 + 9]); } - message->tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * message->num_tiles); - ZeroMemory(message->tiles, sizeof(RFX_TILE*) * message->num_tiles); + message->tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * message->numTiles); + ZeroMemory(message->tiles, sizeof(RFX_TILE*) * message->numTiles); if (context->priv->UseThreads) { - work_objects = (PTP_WORK*) malloc(sizeof(PTP_WORK) * message->num_tiles); - params = (RFX_TILE_WORK_PARAM*) malloc(sizeof(RFX_TILE_WORK_PARAM) * message->num_tiles); + work_objects = (PTP_WORK*) malloc(sizeof(PTP_WORK) * message->numTiles); + params = (RFX_TILE_PROCESS_WORK_PARAM*) malloc(sizeof(RFX_TILE_PROCESS_WORK_PARAM) * message->numTiles); } /* tiles */ - for (i = 0; i < message->num_tiles; i++) + for (i = 0; i < message->numTiles; i++) { + tile = message->tiles[i] = (RFX_TILE*) ObjectPool_Take(context->priv->TilePool); + /* RFX_TILE */ if (Stream_GetRemainingLength(s) < 6) { - DEBUG_WARN("RfxMessageTileSet packet too small to read tile %d/%d", i, message->num_tiles); + DEBUG_WARN("RfxMessageTileSet packet too small to read tile %d/%d", i, message->numTiles); return FALSE; } @@ -703,7 +695,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa if (Stream_GetRemainingLength(s) < blockLen - 6) { - DEBUG_WARN("RfxMessageTileSet not enough bytes to read tile %d/%d with blocklen=%d", i, message->num_tiles, blockLen); + DEBUG_WARN("RfxMessageTileSet not enough bytes to read tile %d/%d with blocklen=%d", i, message->numTiles, blockLen); return FALSE; } @@ -715,13 +707,29 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa break; } - message->tiles[i] = rfx_tile_pool_take(context); + Stream_Read_UINT8(s, tile->quantIdxY); /* quantIdxY (1 byte) */ + Stream_Read_UINT8(s, tile->quantIdxCb); /* quantIdxCb (1 byte) */ + Stream_Read_UINT8(s, tile->quantIdxCr); /* quantIdxCr (1 byte) */ + Stream_Read_UINT16(s, tile->xIdx); /* xIdx (2 bytes) */ + Stream_Read_UINT16(s, tile->yIdx); /* yIdx (2 bytes) */ + Stream_Read_UINT16(s, tile->YLen); /* YLen (2 bytes) */ + Stream_Read_UINT16(s, tile->CbLen); /* CbLen (2 bytes) */ + Stream_Read_UINT16(s, tile->CrLen); /* CrLen (2 bytes) */ + + Stream_GetPointer(s, tile->YData); + Stream_Seek(s, tile->YLen); + Stream_GetPointer(s, tile->CbData); + Stream_Seek(s, tile->CbLen); + Stream_GetPointer(s, tile->CrData); + Stream_Seek(s, tile->CrLen); + + tile->x = tile->xIdx * 64; + tile->y = tile->yIdx * 64; if (context->priv->UseThreads) { params[i].context = context; params[i].tile = message->tiles[i]; - CopyMemory(&(params[i].s), s, sizeof(wStream)); work_objects[i] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_process_message_tile_work_callback, (void*) ¶ms[i], &context->priv->ThreadPoolEnv); @@ -730,7 +738,7 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa } else { - rfx_process_message_tile(context, message->tiles[i], s); + rfx_decode_rgb(context, tile, tile->data, 64 * 4); } Stream_SetPosition(s, pos); @@ -738,12 +746,23 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa if (context->priv->UseThreads) { - for (i = 0; i < message->num_tiles; i++) + for (i = 0; i < message->numTiles; i++) + { WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE); + CloseThreadpoolWork(work_objects[i]); + } free(work_objects); free(params); } + + for (i = 0; i < message->numTiles; i++) + { + tile = message->tiles[i]; + tile->YLen = tile->CbLen = tile->CrLen = 0; + tile->YData = tile->CbData = tile->CrData = NULL; + } + return TRUE; } @@ -758,6 +777,8 @@ RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length message = (RFX_MESSAGE*) malloc(sizeof(RFX_MESSAGE)); ZeroMemory(message, sizeof(RFX_MESSAGE)); + message->freeRects = TRUE; + s = Stream_New(data, length); while (Stream_GetRemainingLength(s) > 6) @@ -844,7 +865,7 @@ RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length UINT16 rfx_message_get_tile_count(RFX_MESSAGE* message) { - return message->num_tiles; + return message->numTiles; } RFX_TILE* rfx_message_get_tile(RFX_MESSAGE* message, int index) @@ -854,7 +875,7 @@ RFX_TILE* rfx_message_get_tile(RFX_MESSAGE* message, int index) UINT16 rfx_message_get_rect_count(RFX_MESSAGE* message) { - return message->num_rects; + return message->numRects; } RFX_RECT* rfx_message_get_rect(RFX_MESSAGE* message, int index) @@ -865,69 +886,45 @@ RFX_RECT* rfx_message_get_rect(RFX_MESSAGE* message, int index) void rfx_message_free(RFX_CONTEXT* context, RFX_MESSAGE* message) { int i; + RFX_TILE* tile; - if (message != NULL) + if (message) { - free(message->rects); + if ((message->rects) && (message->freeRects)) + { + free(message->rects); + } if (message->tiles) { - for (i = 0; i < message->num_tiles; i++) - rfx_tile_pool_return(context, message->tiles[i]); + for (i = 0; i < message->numTiles; i++) + { + tile = message->tiles[i]; + + if (tile->YData) + BufferPool_Return(context->priv->BufferPool, tile->YData); + + if (tile->CbData) + BufferPool_Return(context->priv->BufferPool, tile->CbData); + + if (tile->CrData) + BufferPool_Return(context->priv->BufferPool, tile->CrData); + + ObjectPool_Return(context->priv->TilePool, (void*) tile); + } free(message->tiles); } - free(message); + if (!message->freeArray) + free(message); } } -static void rfx_compose_message_sync(RFX_CONTEXT* context, wStream* s) -{ - Stream_Write_UINT16(s, WBT_SYNC); /* BlockT.blockType */ - Stream_Write_UINT32(s, 12); /* BlockT.blockLen */ - Stream_Write_UINT32(s, WF_MAGIC); /* magic */ - Stream_Write_UINT16(s, WF_VERSION_1_0); /* version */ -} - -static void rfx_compose_message_codec_versions(RFX_CONTEXT* context, wStream* s) -{ - Stream_Write_UINT16(s, WBT_CODEC_VERSIONS); /* BlockT.blockType */ - Stream_Write_UINT32(s, 10); /* BlockT.blockLen */ - Stream_Write_UINT8(s, 1); /* numCodecs */ - Stream_Write_UINT8(s, 1); /* codecs.codecId */ - Stream_Write_UINT16(s, WF_VERSION_1_0); /* codecs.version */ -} - -static void rfx_compose_message_channels(RFX_CONTEXT* context, wStream* s) -{ - Stream_Write_UINT16(s, WBT_CHANNELS); /* BlockT.blockType */ - Stream_Write_UINT32(s, 12); /* BlockT.blockLen */ - Stream_Write_UINT8(s, 1); /* numChannels */ - Stream_Write_UINT8(s, 0); /* Channel.channelId */ - Stream_Write_UINT16(s, context->width); /* Channel.width */ - Stream_Write_UINT16(s, context->height); /* Channel.height */ -} - -static void rfx_compose_message_context(RFX_CONTEXT* context, wStream* s) +static void rfx_update_context_properties(RFX_CONTEXT* context) { UINT16 properties; - Stream_Write_UINT16(s, WBT_CONTEXT); /* CodecChannelT.blockType */ - Stream_Write_UINT32(s, 13); /* CodecChannelT.blockLen */ - Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId */ - Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId */ - Stream_Write_UINT8(s, 0); /* ctxId */ - Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize */ - - /* properties */ - properties = context->flags; /* flags */ - properties |= (COL_CONV_ICT << 3); /* cct */ - properties |= (CLW_XFORM_DWT_53_A << 5); /* xft */ - properties |= ((context->mode == RLGR1 ? CLW_ENTROPY_RLGR1 : CLW_ENTROPY_RLGR3) << 9); /* et */ - properties |= (SCALAR_QUANTIZATION << 13); /* qt */ - Stream_Write_UINT16(s, properties); - /* properties in tilesets: note that this has different format from the one in TS_RFX_CONTEXT */ properties = 1; /* lt */ properties |= (context->flags << 1); /* flags */ @@ -935,22 +932,350 @@ static void rfx_compose_message_context(RFX_CONTEXT* context, wStream* s) properties |= (CLW_XFORM_DWT_53_A << 6); /* xft */ properties |= ((context->mode == RLGR1 ? CLW_ENTROPY_RLGR1 : CLW_ENTROPY_RLGR3) << 10); /* et */ properties |= (SCALAR_QUANTIZATION << 14); /* qt */ + context->properties = properties; } +static void rfx_write_message_sync(RFX_CONTEXT* context, wStream* s) +{ + Stream_Write_UINT16(s, WBT_SYNC); /* BlockT.blockType (2 bytes) */ + Stream_Write_UINT32(s, 12); /* BlockT.blockLen (4 bytes) */ + Stream_Write_UINT32(s, WF_MAGIC); /* magic (4 bytes) */ + Stream_Write_UINT16(s, WF_VERSION_1_0); /* version (2 bytes) */ +} + +static void rfx_write_message_codec_versions(RFX_CONTEXT* context, wStream* s) +{ + Stream_Write_UINT16(s, WBT_CODEC_VERSIONS); /* BlockT.blockType (2 bytes) */ + Stream_Write_UINT32(s, 10); /* BlockT.blockLen (4 bytes) */ + Stream_Write_UINT8(s, 1); /* numCodecs (1 byte) */ + Stream_Write_UINT8(s, 1); /* codecs.codecId (1 byte) */ + Stream_Write_UINT16(s, WF_VERSION_1_0); /* codecs.version (2 bytes) */ +} + +static void rfx_write_message_channels(RFX_CONTEXT* context, wStream* s) +{ + Stream_Write_UINT16(s, WBT_CHANNELS); /* BlockT.blockType (2 bytes) */ + Stream_Write_UINT32(s, 12); /* BlockT.blockLen (4 bytes) */ + Stream_Write_UINT8(s, 1); /* numChannels (1 byte) */ + Stream_Write_UINT8(s, 0); /* Channel.channelId (1 byte) */ + Stream_Write_UINT16(s, context->width); /* Channel.width (2 bytes) */ + Stream_Write_UINT16(s, context->height); /* Channel.height (2 bytes) */ +} + +static void rfx_write_message_context(RFX_CONTEXT* context, wStream* s) +{ + UINT16 properties; + + Stream_Write_UINT16(s, WBT_CONTEXT); /* CodecChannelT.blockType (2 bytes) */ + Stream_Write_UINT32(s, 13); /* CodecChannelT.blockLen (4 bytes) */ + Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId (1 byte) */ + Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId (1 byte) */ + Stream_Write_UINT8(s, 0); /* ctxId (1 byte) */ + Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize (2 bytes) */ + + /* properties */ + properties = context->flags; /* flags */ + properties |= (COL_CONV_ICT << 3); /* cct */ + properties |= (CLW_XFORM_DWT_53_A << 5); /* xft */ + properties |= ((context->mode == RLGR1 ? CLW_ENTROPY_RLGR1 : CLW_ENTROPY_RLGR3) << 9); /* et */ + properties |= (SCALAR_QUANTIZATION << 13); /* qt */ + Stream_Write_UINT16(s, properties); /* properties (2 bytes) */ + + rfx_update_context_properties(context); +} + void rfx_compose_message_header(RFX_CONTEXT* context, wStream* s) { Stream_EnsureRemainingCapacity(s, 12 + 10 + 12 + 13); - rfx_compose_message_sync(context, s); - rfx_compose_message_context(context, s); - rfx_compose_message_codec_versions(context, s); - rfx_compose_message_channels(context, s); - - context->header_processed = TRUE; + rfx_write_message_sync(context, s); + rfx_write_message_context(context, s); + rfx_write_message_codec_versions(context, s); + rfx_write_message_channels(context, s); } -static void rfx_compose_message_frame_begin(RFX_CONTEXT* context, wStream* s) +static int rfx_tile_length(RFX_TILE* tile) +{ + return 19 + tile->YLen + tile->CbLen + tile->CrLen; +} + +static void rfx_write_tile(RFX_CONTEXT* context, wStream* s, RFX_TILE* tile) +{ + UINT32 blockLen; + + blockLen = rfx_tile_length(tile); + Stream_EnsureRemainingCapacity(s, blockLen); + + Stream_Write_UINT16(s, CBT_TILE); /* BlockT.blockType (2 bytes) */ + Stream_Write_UINT32(s, blockLen); /* BlockT.blockLen (4 bytes) */ + Stream_Write_UINT8(s, tile->quantIdxY); /* quantIdxY (1 byte) */ + Stream_Write_UINT8(s, tile->quantIdxCb); /* quantIdxCb (1 byte) */ + Stream_Write_UINT8(s, tile->quantIdxCr); /* quantIdxCr (1 byte) */ + Stream_Write_UINT16(s, tile->xIdx); /* xIdx (2 bytes) */ + Stream_Write_UINT16(s, tile->yIdx); /* yIdx (2 bytes) */ + Stream_Write_UINT16(s, tile->YLen); /* YLen (2 bytes) */ + Stream_Write_UINT16(s, tile->CbLen); /* CbLen (2 bytes) */ + Stream_Write_UINT16(s, tile->CrLen); /* CrLen (2 bytes) */ + Stream_Write(s, tile->YData, tile->YLen); /* YData */ + Stream_Write(s, tile->CbData, tile->CbLen); /* CbData */ + Stream_Write(s, tile->CrData, tile->CrLen); /* CrData */ +} + +struct _RFX_TILE_COMPOSE_WORK_PARAM +{ + RFX_TILE* tile; + RFX_CONTEXT* context; +}; +typedef struct _RFX_TILE_COMPOSE_WORK_PARAM RFX_TILE_COMPOSE_WORK_PARAM; + +void CALLBACK rfx_compose_message_tile_work_callback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work) +{ + RFX_TILE_COMPOSE_WORK_PARAM* param = (RFX_TILE_COMPOSE_WORK_PARAM*) context; + rfx_encode_rgb(param->context, param->tile); +} + +RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, + int numRects, BYTE* data, int width, int height, int scanline) +{ + int i; + int xIdx; + int yIdx; + int numTilesX; + int numTilesY; + UINT16 ax, ay; + RFX_TILE* tile; + RFX_RECT* rect; + int BytesPerPixel; + RFX_MESSAGE* message = NULL; + PTP_WORK* work_objects = NULL; + RFX_TILE_COMPOSE_WORK_PARAM* params = NULL; + + message = (RFX_MESSAGE*) malloc(sizeof(RFX_MESSAGE)); + ZeroMemory(message, sizeof(RFX_MESSAGE)); + + if (context->state == RFX_STATE_SEND_HEADERS) + rfx_update_context_properties(context); + + message->frameIdx = context->frameIdx++; + + message->numRects = numRects; + message->rects = (RFX_RECT*) rects; + + if (!context->numQuant) + { + context->numQuant = 1; + context->quants = (UINT32*) rfx_default_quantization_values; + context->quantIdxY = 0; + context->quantIdxCb = 0; + context->quantIdxCr = 0; + } + + rect = (RFX_RECT*) &rects[0]; + BytesPerPixel = (context->bits_per_pixel / 8); + + message->numQuant = context->numQuant; + message->quantVals = context->quants; + + numTilesX = (width + 63) / 64; + numTilesY = (height + 63) / 64; + + message->numTiles = numTilesX * numTilesY; + message->tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE) * message->numTiles); + ZeroMemory(message->tiles, sizeof(RFX_TILE) * message->numTiles); + + DEBUG_RFX("x: %d y: %d width: %d height: %d scanline: %d BytesPerPixel: %d", + rect->x, rect->y, width, height, scanline, BytesPerPixel); + + if (context->priv->UseThreads) + { + work_objects = (PTP_WORK*) malloc(sizeof(PTP_WORK) * message->numTiles); + params = (RFX_TILE_COMPOSE_WORK_PARAM*) malloc(sizeof(RFX_TILE_COMPOSE_WORK_PARAM) * message->numTiles); + } + + for (yIdx = 0; yIdx < numTilesY; yIdx++) + { + for (xIdx = 0; xIdx < numTilesX; xIdx++) + { + i = yIdx * numTilesX + xIdx; + + tile = message->tiles[i] = (RFX_TILE*) ObjectPool_Take(context->priv->TilePool); + + tile->xIdx = xIdx; + tile->yIdx = yIdx; + tile->x = tile->xIdx * 64; + tile->y = tile->yIdx * 64; + tile->scanline = scanline; + tile->width = (xIdx < numTilesX - 1) ? 64 : width - xIdx * 64; + tile->height = (yIdx < numTilesY - 1) ? 64 : height - yIdx * 64; + + ax = rect->x + tile->x; + ay = rect->y + tile->y; + tile->data = &data[(ay * scanline) + (ax * BytesPerPixel)]; + + tile->quantIdxY = context->quantIdxY; + tile->quantIdxCb = context->quantIdxCb; + tile->quantIdxCr = context->quantIdxCr; + + tile->YLen = 0; + tile->CbLen = 0; + tile->CrLen = 0; + tile->YData = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1); + tile->CbData = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1); + tile->CrData = (BYTE*) BufferPool_Take(context->priv->BufferPool, -1); + + if (context->priv->UseThreads) + { + params[i].context = context; + params[i].tile = tile; + + work_objects[i] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_compose_message_tile_work_callback, + (void*) ¶ms[i], &context->priv->ThreadPoolEnv); + + SubmitThreadpoolWork(work_objects[i]); + } + else + { + rfx_encode_rgb(context, tile); + } + } + } + + message->tilesDataSize = 0; + + for (i = 0; i < message->numTiles; i++) + { + tile = message->tiles[i]; + + if (context->priv->UseThreads) + { + WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE); + CloseThreadpoolWork(work_objects[i]); + } + + message->tilesDataSize += rfx_tile_length(tile); + } + + if (context->priv->UseThreads) + { + free(work_objects); + free(params); + } + + return message; +} + +RFX_MESSAGE* rfx_split_message(RFX_CONTEXT* context, RFX_MESSAGE* message, int* numMessages, int maxDataSize) +{ + int i, j; + UINT32 tileDataSize; + RFX_MESSAGE* messages; + + maxDataSize -= 1024; /* reserve enough space for headers */ + + *numMessages = ((message->tilesDataSize + maxDataSize) / maxDataSize) * 4; + + messages = (RFX_MESSAGE*) malloc(sizeof(RFX_MESSAGE) * (*numMessages)); + ZeroMemory(messages, sizeof(RFX_MESSAGE) * (*numMessages)); + + j = 0; + + for (i = 0; i < message->numTiles; i++) + { + tileDataSize = rfx_tile_length(message->tiles[i]); + + if ((messages[j].tilesDataSize + tileDataSize) > maxDataSize) + j++; + + if (!messages[j].numTiles) + { + messages[j].frameIdx = message->frameIdx + j; + messages[j].numQuant = message->numQuant; + messages[j].quantVals = message->quantVals; + messages[j].numRects = message->numRects; + messages[j].rects = message->rects; + messages[j].tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * message->numTiles); + messages[j].freeRects = FALSE; + messages[j].freeArray = TRUE; + } + + messages[j].tilesDataSize += tileDataSize; + messages[j].tiles[messages[j].numTiles++] = message->tiles[i]; + message->tiles[i] = NULL; + } + + *numMessages = j + 1; + context->frameIdx += j; + message->numTiles = 0; + + for (i = 0; i < *numMessages; i++) + { + for (j = 0; j < messages[i].numTiles; j++) + { + + } + } + + return messages; +} + +RFX_MESSAGE* rfx_encode_messages(RFX_CONTEXT* context, const RFX_RECT* rects, int numRects, + BYTE* data, int width, int height, int scanline, int* numMessages, int maxDataSize) +{ + RFX_MESSAGE* message; + RFX_MESSAGE* messages; + + printf("rfx_encode_messages: numRects: %d maxDataSize: %d x: %d y: %d w: %d/%d h: %d/%d\n", numRects, maxDataSize, + rects[0].x, rects[0].y, rects[0].width, width, rects[0].height, height); + + message = rfx_encode_message(context, rects, numRects, data, width, height, scanline); + messages = rfx_split_message(context, message, numMessages, maxDataSize); + rfx_message_free(context, message); + + return messages; +} + +static void rfx_write_message_tileset(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* message) +{ + int i; + RFX_TILE* tile; + UINT32 blockLen; + UINT32* quantVals; + + blockLen = 22 + (message->numQuant * 5) + message->tilesDataSize; + Stream_EnsureRemainingCapacity(s, blockLen); + + Stream_Write_UINT16(s, WBT_EXTENSION); /* CodecChannelT.blockType (2 bytes) */ + Stream_Write_UINT32(s, blockLen); /* set CodecChannelT.blockLen (4 bytes) */ + Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId (1 byte) */ + Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId (1 byte) */ + Stream_Write_UINT16(s, CBT_TILESET); /* subtype (2 bytes) */ + Stream_Write_UINT16(s, 0); /* idx (2 bytes) */ + Stream_Write_UINT16(s, context->properties); /* properties (2 bytes) */ + Stream_Write_UINT8(s, message->numQuant); /* numQuant (1 byte) */ + Stream_Write_UINT8(s, 0x40); /* tileSize (1 byte) */ + Stream_Write_UINT16(s, message->numTiles); /* numTiles (2 bytes) */ + Stream_Write_UINT32(s, message->tilesDataSize); /* tilesDataSize (4 bytes) */ + + quantVals = message->quantVals; + + for (i = 0; i < message->numQuant * 5; i++) + { + Stream_Write_UINT8(s, quantVals[0] + (quantVals[1] << 4)); + quantVals += 2; + } + + for (i = 0; i < message->numTiles; i++) + { + tile = message->tiles[i]; + rfx_write_tile(context, s, tile); + } + + DEBUG_RFX("numQuant: %d numTiles: %d tilesDataSize: %d", + message->numQuant, message->numTiles, message->tilesDataSize); +} + +void rfx_write_message_frame_begin(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* message) { Stream_EnsureRemainingCapacity(s, 14); @@ -958,172 +1283,46 @@ static void rfx_compose_message_frame_begin(RFX_CONTEXT* context, wStream* s) Stream_Write_UINT32(s, 14); /* CodecChannelT.blockLen */ Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId */ Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId */ - Stream_Write_UINT32(s, context->frame_idx); /* frameIdx */ + Stream_Write_UINT32(s, message->frameIdx); /* frameIdx */ Stream_Write_UINT16(s, 1); /* numRegions */ - - context->frame_idx++; } -static void rfx_compose_message_region(RFX_CONTEXT* context, wStream* s, - const RFX_RECT* rects, int num_rects) -{ - int size; - int i; - - size = 15 + num_rects * 8; - Stream_EnsureRemainingCapacity(s, size); - - Stream_Write_UINT16(s, WBT_REGION); /* CodecChannelT.blockType */ - Stream_Write_UINT32(s, size); /* set CodecChannelT.blockLen later */ - Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId */ - Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId */ - Stream_Write_UINT8(s, 1); /* regionFlags */ - Stream_Write_UINT16(s, num_rects); /* numRects */ - - for (i = 0; i < num_rects; i++) - { - Stream_Write_UINT16(s, rects[i].x); - Stream_Write_UINT16(s, rects[i].y); - Stream_Write_UINT16(s, rects[i].width); - Stream_Write_UINT16(s, rects[i].height); - } - - Stream_Write_UINT16(s, CBT_REGION); /* regionType */ - Stream_Write_UINT16(s, 1); /* numTilesets */ -} - -static void rfx_compose_message_tile(RFX_CONTEXT* context, wStream* s, - BYTE* tile_data, int tile_width, int tile_height, int rowstride, - const UINT32* quantVals, int quantIdxY, int quantIdxCb, int quantIdxCr, - int xIdx, int yIdx) -{ - int YLen = 0; - int CbLen = 0; - int CrLen = 0; - int start_pos, end_pos; - - Stream_EnsureRemainingCapacity(s, 19); - start_pos = Stream_GetPosition(s); - - Stream_Write_UINT16(s, CBT_TILE); /* BlockT.blockType */ - Stream_Seek_UINT32(s); /* set BlockT.blockLen later */ - Stream_Write_UINT8(s, quantIdxY); - Stream_Write_UINT8(s, quantIdxCb); - Stream_Write_UINT8(s, quantIdxCr); - Stream_Write_UINT16(s, xIdx); - Stream_Write_UINT16(s, yIdx); - - Stream_Seek(s, 6); /* YLen, CbLen, CrLen */ - - rfx_encode_rgb(context, tile_data, tile_width, tile_height, rowstride, - quantVals + quantIdxY * 10, quantVals + quantIdxCb * 10, quantVals + quantIdxCr * 10, - s, &YLen, &CbLen, &CrLen); - - DEBUG_RFX("xIdx=%d yIdx=%d width=%d height=%d YLen=%d CbLen=%d CrLen=%d", - xIdx, yIdx, tile_width, tile_height, YLen, CbLen, CrLen); - - end_pos = Stream_GetPosition(s); - - Stream_SetPosition(s, start_pos + 2); - Stream_Write_UINT32(s, 19 + YLen + CbLen + CrLen); /* BlockT.blockLen */ - Stream_SetPosition(s, start_pos + 13); - Stream_Write_UINT16(s, YLen); - Stream_Write_UINT16(s, CbLen); - Stream_Write_UINT16(s, CrLen); - - Stream_SetPosition(s, end_pos); -} - -static void rfx_compose_message_tileset(RFX_CONTEXT* context, wStream* s, - BYTE* image_data, int width, int height, int rowstride) +void rfx_write_message_region(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* message) { int i; - int size; - int start_pos, end_pos; - int numQuants; - const UINT32* quantVals; - const UINT32* quantValsPtr; - int quantIdxY; - int quantIdxCb; - int quantIdxCr; - int numTiles; - int numTilesX; - int numTilesY; - int xIdx; - int yIdx; - int tilesDataSize; + UINT32 blockLen; - if (context->num_quants == 0) + blockLen = 15 + (message->numRects * 8); + Stream_EnsureRemainingCapacity(s, blockLen); + + Stream_Write_UINT16(s, WBT_REGION); /* CodecChannelT.blockType (2 bytes) */ + Stream_Write_UINT32(s, blockLen); /* set CodecChannelT.blockLen (4 bytes) */ + Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId (1 byte) */ + Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId (1 byte) */ + Stream_Write_UINT8(s, 1); /* regionFlags (1 byte) */ + Stream_Write_UINT16(s, message->numRects); /* numRects (2 bytes) */ + + for (i = 0; i < message->numRects; i++) { - numQuants = 1; - quantVals = rfx_default_quantization_values; - quantIdxY = 0; - quantIdxCb = 0; - quantIdxCr = 0; - } - else - { - numQuants = context->num_quants; - quantVals = context->quants; - quantIdxY = context->quant_idx_y; - quantIdxCb = context->quant_idx_cb; - quantIdxCr = context->quant_idx_cr; + /* Clipping rectangles are relative to destLeft, destTop */ + +#if 1 + Stream_Write_UINT16(s, 0); /* x (2 bytes) */ + Stream_Write_UINT16(s, 0); /* y (2 bytes) */ +#else + Stream_Write_UINT16(s, message->rects[i].x); /* x (2 bytes) */ + Stream_Write_UINT16(s, message->rects[i].y); /* y (2 bytes) */ +#endif + + Stream_Write_UINT16(s, message->rects[i].width); /* width (2 bytes) */ + Stream_Write_UINT16(s, message->rects[i].height); /* height (2 bytes) */ } - numTilesX = (width + 63) / 64; - numTilesY = (height + 63) / 64; - numTiles = numTilesX * numTilesY; - - size = 22 + numQuants * 5; - Stream_EnsureRemainingCapacity(s, size); - start_pos = Stream_GetPosition(s); - - Stream_Write_UINT16(s, WBT_EXTENSION); /* CodecChannelT.blockType */ - Stream_Seek_UINT32(s); /* set CodecChannelT.blockLen later */ - Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId */ - Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId */ - Stream_Write_UINT16(s, CBT_TILESET); /* subtype */ - Stream_Write_UINT16(s, 0); /* idx */ - Stream_Write_UINT16(s, context->properties); /* properties */ - Stream_Write_UINT8(s, numQuants); /* numQuants */ - Stream_Write_UINT8(s, 0x40); /* tileSize */ - Stream_Write_UINT16(s, numTiles); /* numTiles */ - Stream_Seek_UINT32(s); /* set tilesDataSize later */ - - quantValsPtr = quantVals; - for (i = 0; i < numQuants * 5; i++) - { - Stream_Write_UINT8(s, quantValsPtr[0] + (quantValsPtr[1] << 4)); - quantValsPtr += 2; - } - - DEBUG_RFX("width:%d height:%d rowstride:%d", width, height, rowstride); - - end_pos = Stream_GetPosition(s); - for (yIdx = 0; yIdx < numTilesY; yIdx++) - { - for (xIdx = 0; xIdx < numTilesX; xIdx++) - { - rfx_compose_message_tile(context, s, - image_data + yIdx * 64 * rowstride + xIdx * 8 * context->bits_per_pixel, - (xIdx < numTilesX - 1) ? 64 : width - xIdx * 64, - (yIdx < numTilesY - 1) ? 64 : height - yIdx * 64, - rowstride, quantVals, quantIdxY, quantIdxCb, quantIdxCr, xIdx, yIdx); - } - } - tilesDataSize = Stream_GetPosition(s) - end_pos; - size += tilesDataSize; - end_pos = Stream_GetPosition(s); - - Stream_SetPosition(s, start_pos + 2); - Stream_Write_UINT32(s, size); /* CodecChannelT.blockLen */ - Stream_SetPosition(s, start_pos + 18); - Stream_Write_UINT32(s, tilesDataSize); - - Stream_SetPosition(s, end_pos); + Stream_Write_UINT16(s, CBT_REGION); /* regionType (2 bytes) */ + Stream_Write_UINT16(s, 1); /* numTilesets (2 bytes) */ } -static void rfx_compose_message_frame_end(RFX_CONTEXT* context, wStream* s) +void rfx_write_message_frame_end(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* message) { Stream_EnsureRemainingCapacity(s, 8); @@ -1133,22 +1332,28 @@ static void rfx_compose_message_frame_end(RFX_CONTEXT* context, wStream* s) Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId */ } -static void rfx_compose_message_data(RFX_CONTEXT* context, wStream* s, - const RFX_RECT* rects, int num_rects, BYTE* image_data, int width, int height, int rowstride) +void rfx_write_message(RFX_CONTEXT* context, wStream* s, RFX_MESSAGE* message) { - rfx_compose_message_frame_begin(context, s); - rfx_compose_message_region(context, s, rects, num_rects); - rfx_compose_message_tileset(context, s, image_data, width, height, rowstride); - rfx_compose_message_frame_end(context, s); -} - -FREERDP_API void rfx_compose_message(RFX_CONTEXT* context, wStream* s, - const RFX_RECT* rects, int num_rects, BYTE* image_data, int width, int height, int rowstride) -{ - /* Only the first frame should send the RemoteFX header */ - if (context->frame_idx == 0 && !context->header_processed) + if (context->state == RFX_STATE_SEND_HEADERS) + { rfx_compose_message_header(context, s); + context->state = RFX_STATE_SEND_FRAME_DATA; + } - rfx_compose_message_data(context, s, rects, num_rects, image_data, width, height, rowstride); + rfx_write_message_frame_begin(context, s, message); + rfx_write_message_region(context, s, message); + rfx_write_message_tileset(context, s, message); + rfx_write_message_frame_end(context, s, message); } +void rfx_compose_message(RFX_CONTEXT* context, wStream* s, + const RFX_RECT* rects, int numRects, BYTE* data, int width, int height, int scanline) +{ + RFX_MESSAGE* message; + + message = rfx_encode_message(context, rects, numRects, data, width, height, scanline); + + rfx_write_message(context, s, message); + + rfx_message_free(context, message); +} diff --git a/libfreerdp/codec/rfx_decode.c b/libfreerdp/codec/rfx_decode.c index 960096f1d..2a642f9da 100644 --- a/libfreerdp/codec/rfx_decode.c +++ b/libfreerdp/codec/rfx_decode.c @@ -103,7 +103,7 @@ static void rfx_decode_component(RFX_CONTEXT* context, const UINT32* quantizatio PROFILER_ENTER(context->priv->prof_rfx_decode_component); PROFILER_ENTER(context->priv->prof_rfx_rlgr_decode); - rfx_rlgr_decode(context->mode, data, size, buffer, 4096); + context->rlgr_decode(context->mode, data, size, buffer, 4096); PROFILER_EXIT(context->priv->prof_rfx_rlgr_decode); PROFILER_ENTER(context->priv->prof_rfx_differential_decode); @@ -125,101 +125,34 @@ static void rfx_decode_component(RFX_CONTEXT* context, const UINT32* quantizatio /* rfx_decode_ycbcr_to_rgb code now resides in the primitives library. */ -struct _RFX_COMPONENT_WORK_PARAM -{ - int size; - INT16* buffer; - const BYTE* data; - RFX_CONTEXT* context; - const UINT32* quantization_values; -}; -typedef struct _RFX_COMPONENT_WORK_PARAM RFX_COMPONENT_WORK_PARAM; - -void CALLBACK rfx_decode_component_work_callback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work) -{ - RFX_COMPONENT_WORK_PARAM* param = (RFX_COMPONENT_WORK_PARAM*) context; - rfx_decode_component(param->context, param->quantization_values, param->data, param->size, param->buffer); -} - /* stride is bytes between rows in the output buffer. */ -BOOL rfx_decode_rgb(RFX_CONTEXT* context, wStream* data_in, - int y_size, const UINT32* y_quants, - int cb_size, const UINT32* cb_quants, - int cr_size, const UINT32* cr_quants, BYTE* rgb_buffer, int stride) +BOOL rfx_decode_rgb(RFX_CONTEXT* context, RFX_TILE* tile, BYTE* rgb_buffer, int stride) { INT16* pSrcDst[3]; + UINT32 *y_quants, *cb_quants, *cr_quants; static const prim_size_t roi_64x64 = { 64, 64 }; const primitives_t *prims = primitives_get(); PROFILER_ENTER(context->priv->prof_rfx_decode_rgb); + y_quants = context->quants + (tile->quantIdxY * 10); + cb_quants = context->quants + (tile->quantIdxCb * 10); + cr_quants = context->quants + (tile->quantIdxCr * 10); + pSrcDst[0] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* y_r_buffer */ pSrcDst[1] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* cb_g_buffer */ pSrcDst[2] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* cr_b_buffer */ -#if 0 - if (context->priv->UseThreads) - { - PTP_WORK work_objects[3]; - RFX_COMPONENT_WORK_PARAM params[3]; + rfx_decode_component(context, y_quants, tile->YData, tile->YLen, pSrcDst[0]); /* YData */ - params[0].context = context; - params[0].quantization_values = y_quants; - params[0].buffer = Stream_Pointer(data_in); - params[0].capacity = y_size; - params[0].buffer = pSrcDst[0]; - Stream_Seek(data_in, y_size); + rfx_decode_component(context, cb_quants, tile->CbData, tile->CbLen, pSrcDst[1]); /* CbData */ - params[1].context = context; - params[1].quantization_values = cb_quants; - params[1].buffer = Stream_Pointer(data_in); - params[1].capacity = cb_size; - params[1].buffer = pSrcDst[1]; - Stream_Seek(data_in, cb_size); - - params[2].context = context; - params[2].quantization_values = cr_quants; - params[2].buffer = Stream_Pointer(data_in); - params[2].capacity = cr_size; - params[2].buffer = pSrcDst[2]; - Stream_Seek(data_in, cr_size); - - work_objects[0] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_decode_component_work_callback, - (void*) ¶ms[0], &context->priv->ThreadPoolEnv); - work_objects[1] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_decode_component_work_callback, - (void*) ¶ms[1], &context->priv->ThreadPoolEnv); - work_objects[2] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_decode_component_work_callback, - (void*) ¶ms[2], &context->priv->ThreadPoolEnv); - - SubmitThreadpoolWork(work_objects[0]); - SubmitThreadpoolWork(work_objects[1]); - SubmitThreadpoolWork(work_objects[2]); - - WaitForThreadpoolWorkCallbacks(work_objects[0], FALSE); - WaitForThreadpoolWorkCallbacks(work_objects[1], FALSE); - WaitForThreadpoolWorkCallbacks(work_objects[2], FALSE); - } - else -#endif - { - if (Stream_GetRemainingLength(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_Pointer(data_in), y_size, pSrcDst[0]); /* YData */ - Stream_Seek(data_in, y_size); - - rfx_decode_component(context, cb_quants, Stream_Pointer(data_in), cb_size, pSrcDst[1]); /* CbData */ - Stream_Seek(data_in, cb_size); - - rfx_decode_component(context, cr_quants, Stream_Pointer(data_in), cr_size, pSrcDst[2]); /* CrData */ - Stream_Seek(data_in, cr_size); - } + rfx_decode_component(context, cr_quants, tile->CrData, tile->CrLen, pSrcDst[2]); /* CrData */ + PROFILER_ENTER(context->priv->prof_rfx_ycbcr_to_rgb); prims->yCbCrToRGB_16s16s_P3P3((const INT16**) pSrcDst, 64 * sizeof(INT16), pSrcDst, 64 * sizeof(INT16), &roi_64x64); + PROFILER_EXIT(context->priv->prof_rfx_ycbcr_to_rgb); PROFILER_ENTER(context->priv->prof_rfx_decode_format_rgb); rfx_decode_format_rgb(pSrcDst[0], pSrcDst[1], pSrcDst[2], diff --git a/libfreerdp/codec/rfx_decode.h b/libfreerdp/codec/rfx_decode.h index 469c2a576..f5da4f933 100644 --- a/libfreerdp/codec/rfx_decode.h +++ b/libfreerdp/codec/rfx_decode.h @@ -23,11 +23,7 @@ #include /* stride is bytes between rows in the output buffer. */ -BOOL rfx_decode_rgb(RFX_CONTEXT* context, wStream* data_in, - int y_size, const UINT32 * y_quants, - int cb_size, const UINT32 * cb_quants, - int cr_size, const UINT32 * cr_quants, BYTE* rgb_buffer, - int stride); +BOOL rfx_decode_rgb(RFX_CONTEXT* context, RFX_TILE* tile, BYTE* rgb_buffer, int stride); #endif /* __RFX_DECODE_H */ diff --git a/libfreerdp/codec/rfx_encode.c b/libfreerdp/codec/rfx_encode.c index b59570bec..f484e58fd 100644 --- a/libfreerdp/codec/rfx_encode.c +++ b/libfreerdp/codec/rfx_encode.c @@ -174,9 +174,9 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i while (y_exceed > 0) { - memcpy(r_buf, r_last, 64 * sizeof(INT16)); - memcpy(g_buf, g_last, 64 * sizeof(INT16)); - memcpy(b_buf, b_last, 64 * sizeof(INT16)); + CopyMemory(r_buf, r_last, 64 * sizeof(INT16)); + CopyMemory(g_buf, g_last, 64 * sizeof(INT16)); + CopyMemory(b_buf, b_last, 64 * sizeof(INT16)); r_buf += 64; g_buf += 64; b_buf += 64; @@ -209,7 +209,7 @@ static void rfx_encode_component(RFX_CONTEXT* context, const UINT32* quantizatio PROFILER_EXIT(context->priv->prof_rfx_differential_encode); PROFILER_ENTER(context->priv->prof_rfx_rlgr_encode); - *size = rfx_rlgr_encode(context->mode, data, 4096, buffer, buffer_size); + *size = context->rlgr_encode(context->mode, data, 4096, buffer, buffer_size); PROFILER_EXIT(context->priv->prof_rfx_rlgr_encode); PROFILER_EXIT(context->priv->prof_rfx_encode_component); @@ -217,14 +217,19 @@ static void rfx_encode_component(RFX_CONTEXT* context, const UINT32* quantizatio BufferPool_Return(context->priv->BufferPool, dwt_buffer); } -void rfx_encode_rgb(RFX_CONTEXT* context, const BYTE* rgb_data, int width, int height, int rowstride, - const UINT32* y_quants, const UINT32* cb_quants, const UINT32* cr_quants, - wStream* data_out, int* y_size, int* cb_size, int* cr_size) +void rfx_encode_rgb(RFX_CONTEXT* context, RFX_TILE* tile) { INT16* pSrcDst[3]; + int YLen, CbLen, CrLen; + UINT32 *YQuant, *CbQuant, *CrQuant; primitives_t* prims = primitives_get(); static const prim_size_t roi_64x64 = { 64, 64 }; + YLen = CbLen = CrLen = 0; + YQuant = context->quants + (tile->quantIdxY * 10); + CbQuant = context->quants + (tile->quantIdxCb * 10); + CrQuant = context->quants + (tile->quantIdxCr * 10); + pSrcDst[0] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* y_r_buffer */ pSrcDst[1] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* cb_g_buffer */ pSrcDst[2] = (INT16*)((BYTE*)BufferPool_Take(context->priv->BufferPool, -1) + 16); /* cr_b_buffer */ @@ -232,7 +237,7 @@ void rfx_encode_rgb(RFX_CONTEXT* context, const BYTE* rgb_data, int width, int h PROFILER_ENTER(context->priv->prof_rfx_encode_rgb); PROFILER_ENTER(context->priv->prof_rfx_encode_format_rgb); - rfx_encode_format_rgb(rgb_data, width, height, rowstride, + rfx_encode_format_rgb(tile->data, tile->width, tile->height, tile->scanline, context->pixel_format, context->palette, pSrcDst[0], pSrcDst[1], pSrcDst[2]); PROFILER_EXIT(context->priv->prof_rfx_encode_format_rgb); @@ -241,22 +246,22 @@ void rfx_encode_rgb(RFX_CONTEXT* context, const BYTE* rgb_data, int width, int h pSrcDst, 64 * sizeof(INT16), &roi_64x64); PROFILER_EXIT(context->priv->prof_rfx_rgb_to_ycbcr); - /* Ensure the buffer is reasonably large enough */ - Stream_EnsureRemainingCapacity(data_out, 4096); + /** + * We need to clear the buffers as the RLGR encoder expects it to be initialized to zero. + * This allows simplifying and improving the performance of the encoding process. + */ - rfx_encode_component(context, y_quants, pSrcDst[0], - Stream_Pointer(data_out), Stream_GetRemainingLength(data_out), y_size); - Stream_Seek(data_out, *y_size); + ZeroMemory(tile->YData, 4096); + ZeroMemory(tile->CbData, 4096); + ZeroMemory(tile->CrData, 4096); - Stream_EnsureRemainingCapacity(data_out, 4096); - rfx_encode_component(context, cb_quants, pSrcDst[1], - Stream_Pointer(data_out), Stream_GetRemainingLength(data_out), cb_size); - Stream_Seek(data_out, *cb_size); + rfx_encode_component(context, YQuant, pSrcDst[0], tile->YData, 4096, &YLen); + rfx_encode_component(context, CbQuant, pSrcDst[1], tile->CbData, 4096, &CbLen); + rfx_encode_component(context, CrQuant, pSrcDst[2], tile->CrData, 4096, &CrLen); - Stream_EnsureRemainingCapacity(data_out, 4096); - rfx_encode_component(context, cr_quants, pSrcDst[2], - Stream_Pointer(data_out), Stream_GetRemainingLength(data_out), cr_size); - Stream_Seek(data_out, *cr_size); + tile->YLen = (UINT16) YLen; + tile->CbLen = (UINT16) CbLen; + tile->CrLen = (UINT16) CrLen; PROFILER_EXIT(context->priv->prof_rfx_encode_rgb); diff --git a/libfreerdp/codec/rfx_encode.h b/libfreerdp/codec/rfx_encode.h index e329bded2..28bc96651 100644 --- a/libfreerdp/codec/rfx_encode.h +++ b/libfreerdp/codec/rfx_encode.h @@ -22,9 +22,7 @@ #include -void rfx_encode_rgb(RFX_CONTEXT* context, const BYTE* rgb_data, int width, int height, int rowstride, - const UINT32* y_quants, const UINT32* cb_quants, const UINT32* cr_quants, - wStream* data_out, int* y_size, int* cb_size, int* cr_size); +void rfx_encode_rgb(RFX_CONTEXT* context, RFX_TILE* tile); #endif diff --git a/libfreerdp/codec/rfx_types.h b/libfreerdp/codec/rfx_types.h index 80ae12511..fbb4df837 100644 --- a/libfreerdp/codec/rfx_types.h +++ b/libfreerdp/codec/rfx_types.h @@ -39,8 +39,7 @@ struct _RFX_CONTEXT_PRIV { - wQueue* TilePool; - wQueue* TileQueue; + wObjectPool* TilePool; BOOL UseThreads; DWORD MinThreadCount; diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index c85f2a120..59eeb92e8 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -562,14 +562,14 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id) return settings->PlayRemoteFx; break; - case FreeRDP_GatewayUsageMethod: - return settings->GatewayUsageMethod; - break; - case FreeRDP_GatewayUseSameCredentials: return settings->GatewayUseSameCredentials; break; + case FreeRDP_GatewayEnabled: + return settings->GatewayEnabled; + break; + case FreeRDP_RemoteApplicationMode: return settings->RemoteApplicationMode; break; @@ -658,6 +658,10 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id) return settings->MultiTouchInput; break; + case FreeRDP_MultiTouchGestures: + return settings->MultiTouchGestures; + break; + case FreeRDP_SoundBeepsEnabled: return settings->SoundBeepsEnabled; break; @@ -1013,14 +1017,14 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) settings->PlayRemoteFx = param; break; - case FreeRDP_GatewayUsageMethod: - settings->GatewayUsageMethod = param; - break; - case FreeRDP_GatewayUseSameCredentials: settings->GatewayUseSameCredentials = param; break; + case FreeRDP_GatewayEnabled: + settings->GatewayEnabled = param; + break; + case FreeRDP_RemoteApplicationMode: settings->RemoteApplicationMode = param; break; @@ -1109,6 +1113,10 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) settings->MultiTouchInput = param; break; + case FreeRDP_MultiTouchGestures: + settings->MultiTouchGestures = param; + break; + case FreeRDP_SoundBeepsEnabled: settings->SoundBeepsEnabled = param; break; @@ -1199,11 +1207,60 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) EventArgsInit(&e, "freerdp"); e.id = id; - PubSub_OnParamChange(context->pubSub, context->instance, &e); + PubSub_OnParamChange(context->pubSub, context, &e); return -1; } +int freerdp_get_param_int(rdpSettings* settings, int id) +{ + switch (id) + { + case FreeRDP_XPan: + return settings->XPan; + break; + + case FreeRDP_YPan: + return settings->YPan; + break; + + default: + return 0; + break; + } + + return 0; +} + +int freerdp_set_param_int(rdpSettings* settings, int id, int param) +{ + ParamChangeEventArgs e; + rdpContext* context = ((freerdp*) settings->instance)->context; + + switch (id) + { + case FreeRDP_XPan: + settings->XPan = param; + break; + + case FreeRDP_YPan: + settings->YPan = param; + break; + + default: + return -1; + break; + } + + settings->settings_modified[id] = 1; + + EventArgsInit(&e, "freerdp"); + e.id = id; + PubSub_OnParamChange(context->pubSub, context, &e); + + return 0; +} + UINT32 freerdp_get_param_uint32(rdpSettings* settings, int id) { switch (id) @@ -1360,6 +1417,10 @@ UINT32 freerdp_get_param_uint32(rdpSettings* settings, int id) return settings->PercentScreen; break; + case FreeRDP_GatewayUsageMethod: + return settings->GatewayUsageMethod; + break; + case FreeRDP_GatewayPort: return settings->GatewayPort; break; @@ -1679,6 +1740,10 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param) settings->PercentScreen = param; break; + case FreeRDP_GatewayUsageMethod: + settings->GatewayUsageMethod = param; + break; + case FreeRDP_GatewayPort: settings->GatewayPort = param; break; @@ -1841,7 +1906,7 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param) EventArgsInit(&e, "freerdp"); e.id = id; - PubSub_OnParamChange(context->pubSub, context->instance, &e); + PubSub_OnParamChange(context->pubSub, context, &e); return 0; } @@ -1883,7 +1948,7 @@ int freerdp_set_param_uint64(rdpSettings* settings, int id, UINT64 param) EventArgsInit(&e, "freerdp"); e.id = id; - PubSub_OnParamChange(context->pubSub, context->instance, &e); + PubSub_OnParamChange(context->pubSub, context, &e); return 0; } @@ -2221,7 +2286,49 @@ int freerdp_set_param_string(rdpSettings* settings, int id, char* param) EventArgsInit(&e, "freerdp"); e.id = id; - PubSub_OnParamChange(context->pubSub, context->instance, &e); + PubSub_OnParamChange(context->pubSub, context, &e); return 0; } + +double freerdp_get_param_double(rdpSettings* settings, int id) +{ + switch (id) + { + case FreeRDP_ScalingFactor: + return settings->ScalingFactor; + break; + + default: + return 0; + break; + } + + return 0; +} + +int freerdp_set_param_double(rdpSettings* settings, int id, double param) +{ + ParamChangeEventArgs e; + rdpContext* context = ((freerdp*) settings->instance)->context; + + switch (id) + { + case FreeRDP_ScalingFactor: + settings->ScalingFactor = param; + break; + + default: + return -1; + break; + } + + settings->settings_modified[id] = 1; + + EventArgsInit(&e, "freerdp"); + e.id = id; + PubSub_OnParamChange(context->pubSub, context, &e); + + return 0; +} + diff --git a/libfreerdp/core/activation.c b/libfreerdp/core/activation.c index 58d80ed82..edc31a295 100644 --- a/libfreerdp/core/activation.c +++ b/libfreerdp/core/activation.c @@ -250,6 +250,7 @@ BOOL rdp_recv_server_font_map_pdu(rdpRdp* rdp, wStream* s) BOOL rdp_recv_client_font_map_pdu(rdpRdp* rdp, wStream* s) { rdp->finalize_sc_pdus |= FINALIZE_SC_FONT_MAP_PDU; + if(Stream_GetRemainingLength(s) >= 8) { Stream_Seek_UINT16(s); /* numberEntries (2 bytes) */ @@ -279,6 +280,11 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s) { UINT16 lengthSourceDescriptor; + if (rdp->state == CONNECTION_STATE_ACTIVE) + rdp->deactivation_reactivation = TRUE; + else + rdp->deactivation_reactivation = FALSE; + /* * Windows XP can send short DEACTIVATE_ALL PDU that doesn't contain * the following fields. @@ -305,7 +311,7 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s) while(0); } - rdp->state = CONNECTION_STATE_CAPABILITY; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); while (rdp->state != CONNECTION_STATE_ACTIVE) { @@ -362,6 +368,8 @@ BOOL rdp_server_accept_client_font_list_pdu(rdpRdp* rdp, wStream* s) if (!rdp_send_server_font_map_pdu(rdp)) return FALSE; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_ACTIVE); + return TRUE; } diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 4d69b4ed7..4da339677 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -185,6 +185,8 @@ BOOL rdp_read_general_capability_set(wStream* s, UINT16 length, rdpSettings* set Stream_Read_UINT8(s, refreshRectSupport); /* refreshRectSupport (1 byte) */ Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */ + settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE; + if (!(extraFlags & FASTPATH_OUTPUT_SUPPORTED)) settings->FastPathOutput = FALSE; @@ -213,7 +215,10 @@ void rdp_write_general_capability_set(wStream* s, rdpSettings* settings) header = rdp_capability_set_start(s); - extraFlags = LONG_CREDENTIALS_SUPPORTED | NO_BITMAP_COMPRESSION_HDR; + extraFlags = LONG_CREDENTIALS_SUPPORTED; + + if (settings->NoBitmapCompressionHeader) + extraFlags |= NO_BITMAP_COMPRESSION_HDR; if (settings->AutoReconnectionEnabled) extraFlags |= AUTORECONNECT_SUPPORTED; @@ -1209,7 +1214,7 @@ BOOL rdp_read_input_capability_set(wStream* s, UINT16 length, rdpSettings* setti Stream_Seek(s, 64); /* imeFileName (64 bytes) */ - if (settings->ServerMode != TRUE) + if (!settings->ServerMode) { if (inputFlags & INPUT_FLAG_FASTPATH_INPUT) { @@ -1217,7 +1222,7 @@ BOOL rdp_read_input_capability_set(wStream* s, UINT16 length, rdpSettings* setti } else if (inputFlags & INPUT_FLAG_FASTPATH_INPUT2) { - /* avertised by RDP 5.2, 6.0, 6.1 and 7.0 servers */ + /* advertised by RDP 5.2, 6.0, 6.1 and 7.0 servers */ } else { @@ -1440,17 +1445,25 @@ void rdp_write_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_defini BOOL rdp_read_glyph_cache_capability_set(wStream* s, UINT16 length, rdpSettings* settings) { - UINT16 glyphSupportLevel; - if (length < 52) return FALSE; - Stream_Seek(s, 40); /* glyphCache (40 bytes) */ - Stream_Seek_UINT32(s); /* fragCache (4 bytes) */ - Stream_Read_UINT16(s, glyphSupportLevel); /* glyphSupportLevel (2 bytes) */ - Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */ + /* glyphCache (40 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[0])); /* glyphCache0 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[1])); /* glyphCache1 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[2])); /* glyphCache2 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[3])); /* glyphCache3 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[4])); /* glyphCache4 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[5])); /* glyphCache5 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[6])); /* glyphCache6 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[7])); /* glyphCache7 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[8])); /* glyphCache8 (4 bytes) */ + rdp_read_cache_definition(s, &(settings->GlyphCache[9])); /* glyphCache9 (4 bytes) */ + rdp_read_cache_definition(s, settings->FragCache); /* fragCache (4 bytes) */ - settings->GlyphSupportLevel = glyphSupportLevel; + Stream_Read_UINT16(s, settings->GlyphSupportLevel); /* glyphSupportLevel (2 bytes) */ + + Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */ return TRUE; } @@ -2313,10 +2326,14 @@ BOOL rdp_print_multifragment_update_capability_set(wStream* s, UINT16 length) BOOL rdp_read_large_pointer_capability_set(wStream* s, UINT16 length, rdpSettings* settings) { + UINT16 largePointerSupportFlags; + if (length < 6) return FALSE; - Stream_Seek_UINT16(s); /* largePointerSupportFlags (2 bytes) */ + Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */ + + settings->LargePointerFlag = (largePointerSupportFlags & LARGE_POINTER_FLAG_96x96) ? 1 : 0; return TRUE; } @@ -2862,6 +2879,7 @@ BOOL rdp_read_frame_acknowledge_capability_set(wStream* s, UINT16 length, rdpSet { Stream_Seek_UINT32(s); /* (4 bytes) */ } + return TRUE; } @@ -2874,14 +2892,12 @@ BOOL rdp_read_frame_acknowledge_capability_set(wStream* s, UINT16 length, rdpSet void rdp_write_frame_acknowledge_capability_set(wStream* s, rdpSettings* settings) { int header; - UINT32 frame_acknowledge; Stream_EnsureRemainingCapacity(s, 32); header = rdp_capability_set_start(s); - frame_acknowledge = settings->FrameAcknowledge; - Stream_Write_UINT32(s, frame_acknowledge); /* (4 bytes) */ + Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */ rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE); } @@ -3501,24 +3517,13 @@ BOOL rdp_send_demand_active(rdpRdp* rdp) BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s) { - UINT16 channelId; - UINT16 pduType; - UINT16 pduLength; - UINT16 pduSource; + BOOL status; + rdpSettings* settings; UINT16 lengthSourceDescriptor; UINT16 lengthCombinedCapabilities; UINT16 numberCapabilities; - if (!rdp_recv_get_active_header(rdp, s, &channelId)) - return FALSE; - - if (!rdp_read_share_control_header(s, &pduLength, &pduType, &pduSource)) - return FALSE; - - rdp->settings->PduSource = pduSource; - - if (pduType != PDU_TYPE_CONFIRM_ACTIVE) - return FALSE; + settings = rdp->settings; if (Stream_GetRemainingLength(s) < 10) return FALSE; @@ -3535,7 +3540,46 @@ BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */ Stream_Seek(s, 2); /* pad2Octets (2 bytes) */ - return rdp_read_capability_sets(s, rdp->settings, numberCapabilities); + status = rdp_read_capability_sets(s, rdp->settings, numberCapabilities); + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS]) + { + /* client does not support surface commands */ + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE]) + { + /* client does not support frame acks */ + settings->FrameAcknowledge = 0; + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID]) + { + /* client does not support bitmap cache v3 */ + settings->BitmapCacheV3Enabled = FALSE; + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS]) + { + /* client does not support bitmap codecs */ + + settings->RemoteFxCodec = FALSE; + settings->NSCodec = FALSE; + settings->JpegCodec = FALSE; + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE]) + { + /* client does not support multi fragment updates */ + } + + if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER]) + { + /* client does not support large pointers */ + settings->LargePointerFlag = 0; + } + + return status; } void rdp_write_confirm_active(wStream* s, rdpSettings* settings) @@ -3628,17 +3672,13 @@ void rdp_write_confirm_active(wStream* s, rdpSettings* settings) rdp_write_bitmap_codecs_capability_set(s, settings); } - if (settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE]) - { - if (settings->FrameAcknowledge > 0) - { - numberCapabilities++; - rdp_write_frame_acknowledge_capability_set(s, settings); - } - } - else - { + if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE]) settings->FrameAcknowledge = 0; + + if (settings->FrameAcknowledge) + { + numberCapabilities++; + rdp_write_frame_acknowledge_capability_set(s, settings); } if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID]) diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 2ce41eb11..e2cfdc283 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -30,6 +30,7 @@ #include #include +#include /** * Connection Sequence\n @@ -61,6 +62,103 @@ * */ +/** + * + * Connection Sequence + * + * 1. Connection Initiation: The client initiates the connection by sending the server a + * Class 0 X.224 Connection Request PDU (section 2.2.1.1). The server responds with a + * Class 0 X.224 Connection Confirm PDU (section 2.2.1.2). From this point, all subsequent + * data sent between client and server is wrapped in an X.224 Data Protocol Data Unit (PDU). + * + * 2. Basic Settings Exchange: Basic settings are exchanged between the client and server by + * using the MCS Connect Initial PDU (section 2.2.1.3) and MCS Connect Response PDU (section 2.2.1.4). + * The Connect Initial PDU contains a Generic Conference Control (GCC) Conference Create Request, + * while the Connect Response PDU contains a GCC Conference Create Response. These two GCC packets + * contain concatenated blocks of settings data (such as core data, security data, and network data) + * which are read by client and server. + * + * 3. Channel Connection: The client sends an MCS Erect Domain Request PDU (section 2.2.1.5), + * followed by an MCS Attach User Request PDU (section 2.2.1.6) to attach the primary user identity + * to the MCS domain. The server responds with an MCS Attach User Confirm PDU (section 2.2.1.7) + * containing the User Channel ID. The client then proceeds to join the user channel, the + * input/output (I/O) channel, and all of the static virtual channels (the I/O and static virtual + * channel IDs are obtained from the data embedded in the GCC packets) by using multiple MCS Channel + * Join Request PDUs (section 2.2.1.8). The server confirms each channel with an MCS Channel Join + * Confirm PDU (section 2.2.1.9). (The client only sends a Channel Join Request after it has received + * the Channel Join Confirm for the previously sent request.) + * + * From this point, all subsequent data sent from the client to the server is wrapped in an MCS Send + * Data Request PDU, while data sent from the server to the client is wrapped in an MCS Send Data + * Indication PDU. This is in addition to the data being wrapped by an X.224 Data PDU. + * + * 4. RDP Security Commencement: If Standard RDP Security mechanisms (section 5.3) are being employed and + * encryption is in force (this is determined by examining the data embedded in the GCC Conference Create + * Response packet) then the client sends a Security Exchange PDU (section 2.2.1.10) containing an encrypted + * 32-byte random number to the server. This random number is encrypted with the public key of the server + * as described in section 5.3.4.1 (the server's public key, as well as a 32-byte server-generated random + * number, are both obtained from the data embedded in the GCC Conference Create Response packet). The client + * and server then utilize the two 32-byte random numbers to generate session keys which are used to encrypt + * and validate the integrity of subsequent RDP traffic. + * + * From this point, all subsequent RDP traffic can be encrypted and a security header is included with the + * data if encryption is in force. (The Client Info PDU (section 2.2.1.11) and licensing PDUs ([MS-RDPELE] + * section 2.2.2) are an exception in that they always have a security header). The Security Header follows + * the X.224 and MCS Headers and indicates whether the attached data is encrypted. Even if encryption is in + * force, server-to-client traffic may not always be encrypted, while client-to-server traffic must always be + * encrypted (encryption of licensing PDUs is optional, however). + * + * 5. Secure Settings Exchange: Secure client data (such as the username, password, and auto-reconnect cookie) + * is sent to the server by using the Client Info PDU (section 2.2.1.11). + * + * 6. Optional Connect-Time Auto-Detection: During the optional connect-time auto-detect phase the goal is to + * determine characteristics of the network, such as the round-trip latency time and the bandwidth of the link + * between the server and client. This is accomplished by exchanging a collection of PDUs (specified in section 2.2.1.4) + * over a predetermined period of time with enough data to ensure that the results are statistically relevant. + * + * 7. Licensing: The goal of the licensing exchange is to transfer a license from the server to the client. + * The client stores this license and on subsequent connections sends the license to the server for validation. + * However, in some situations the client may not be issued a license to store. In effect, the packets exchanged + * during this phase of the protocol depend on the licensing mechanisms employed by the server. Within the context + * of this document, it is assumed that the client will not be issued a license to store. For details regarding + * more advanced licensing scenarios that take place during the Licensing Phase, see [MS-RDPELE] section 1.3. + * + * 8. Optional Multitransport Bootstrapping: After the connection has been secured and the Licensing Phase has run + * to completion, the server can choose to initiate multitransport connections ([MS-RDPEMT] section 1.3). + * The Initiate Multitransport Request PDU (section 2.2.15.1) is sent by the server to the client and results + * in the out-of-band creation of a multitransport connection using messages from the RDP-UDP, TLS, DTLS, and + * multitransport protocols ([MS-RDPEMT] section 1.3.1). + * + * 9. Capabilities Exchange: The server sends the set of capabilities it supports to the client in a Demand Active PDU + * (section 2.2.1.13.1). The client responds with its capabilities by sending a Confirm Active PDU (section 2.2.1.13.2). + * + * 10. Connection Finalization: The client and server exchange PDUs to finalize the connection details. The client-to-server + * PDUs sent during this phase have no dependencies on any of the server-to-client PDUs; they may be sent as a single batch, + * provided that sequencing is maintained. + * + * - The Client Synchronize PDU (section 2.2.1.14) is sent after transmitting the Confirm Active PDU. + * - The Client Control (Cooperate) PDU (section 2.2.1.15) is sent after transmitting the Client Synchronize PDU. + * - The Client Control (Request Control) PDU (section 2.2.1.16) is sent after transmitting the Client Control (Cooperate) PDU. + * - The optional Persistent Key List PDUs (section 2.2.1.17) are sent after transmitting the Client Control (Request Control) PDU. + * - The Font List PDU (section 2.2.1.18) is sent after transmitting the Persistent Key List PDUs or, if the Persistent Key List + * PDUs were not sent, it is sent after transmitting the Client Control (Request Control) PDU (section 2.2.1.16). + * + * The server-to-client PDUs sent during the Connection Finalization Phase have dependencies on the client-to-server PDUs. + * + * - The optional Monitor Layout PDU (section 2.2.12.1) has no dependency on any client-to-server PDUs and is sent after the Demand Active PDU. + * - The Server Synchronize PDU (section 2.2.1.19) is sent in response to the Confirm Active PDU. + * - The Server Control (Cooperate) PDU (section 2.2.1.20) is sent after transmitting the Server Synchronize PDU. + * - The Server Control (Granted Control) PDU (section 2.2.1.21) is sent in response to the Client Control (Request Control) PDU. + * - The Font Map PDU (section 2.2.1.22) is sent in response to the Font List PDU. + * + * Once the client has sent the Confirm Active PDU, it can start sending mouse and keyboard input to the server, and upon receipt + * of the Font List PDU the server can start sending graphics output to the client. + * + * Besides input and graphics data, other data that can be exchanged between client and server after the connection has been + * finalized includes connection management information and virtual channel messages (exchanged between client-side plug-ins + * and server-side applications). + */ + /** * Establish RDP Connection based on the settings given in the 'rdp' parameter. * @msdn{cc240452} @@ -75,17 +173,20 @@ BOOL rdp_client_connect(rdpRdp* rdp) nego_init(rdp->nego); nego_set_target(rdp->nego, settings->ServerHostname, settings->ServerPort); - if (settings->GatewayUsageMethod) + if (settings->GatewayEnabled) { char* user; char* domain; char* cookie; - int user_length; + int user_length = 0; int domain_length; int cookie_length; - user = settings->Username; - user_length = strlen(settings->Username); + if (settings->Username) + { + user = settings->Username; + user_length = strlen(settings->Username); + } if (settings->Domain) domain = settings->Domain; @@ -100,7 +201,10 @@ BOOL rdp_client_connect(rdpRdp* rdp) CopyMemory(cookie, domain, domain_length); CharUpperBuffA(cookie, domain_length); cookie[domain_length] = '\\'; - CopyMemory(&cookie[domain_length + 1], user, user_length); + + if (settings->Username) + CopyMemory(&cookie[domain_length + 1], user, user_length); + cookie[cookie_length] = '\0'; nego_set_cookie(rdp->nego, cookie); @@ -152,7 +256,8 @@ BOOL rdp_client_connect(rdpRdp* rdp) } rdp_set_blocking_mode(rdp, FALSE); - rdp->state = CONNECTION_STATE_NEGO; + + rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO); rdp->finalize_sc_pdus = 0; if (!mcs_send_connect_initial(rdp->mcs)) @@ -187,24 +292,38 @@ BOOL rdp_client_redirect(rdpRdp* rdp) rdp_client_disconnect(rdp); /* FIXME: this is a subset of rdp_free */ + /* --> this should really go into rdp.c */ crypto_rc4_free(rdp->rc4_decrypt_key); + rdp->rc4_decrypt_key = NULL ; crypto_rc4_free(rdp->rc4_encrypt_key); + rdp->rc4_encrypt_key = NULL; crypto_des3_free(rdp->fips_encrypt); + rdp->fips_encrypt = NULL ; crypto_des3_free(rdp->fips_decrypt); + rdp->fips_decrypt = NULL ; crypto_hmac_free(rdp->fips_hmac); + rdp->fips_hmac = NULL ; + + free(settings->ServerRandom); + settings->ServerRandom = NULL ; + free(settings->ServerCertificate); + settings->ServerCertificate = NULL ; + free(settings->ClientAddress); + settings->ClientAddress = NULL ; + + mppc_enc_free(rdp->mppc_enc); + mppc_dec_free(rdp->mppc_dec); mcs_free(rdp->mcs); nego_free(rdp->nego); license_free(rdp->license); transport_free(rdp->transport); - free(settings->ServerRandom); - free(settings->ServerCertificate); - free(settings->ClientAddress); - rdp->transport = transport_new(settings); rdp->license = license_new(rdp); rdp->nego = nego_new(rdp->transport); rdp->mcs = mcs_new(rdp->transport); + rdp->mppc_dec = mppc_dec_new(); + rdp->mppc_enc = mppc_enc_new(PROTO_RDP_50); rdp->transport->layer = TRANSPORT_LAYER_TCP; settings->RedirectedSessionId = redirection->sessionID; @@ -263,7 +382,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) BYTE crypt_client_random[256 + 8]; BYTE client_random[CLIENT_RANDOM_LENGTH]; - if (rdp->settings->DisableEncryption == FALSE) + if (!rdp->settings->DisableEncryption) { /* no RDP encryption */ return TRUE; @@ -323,7 +442,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) return TRUE; } -static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) +BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) { BYTE client_random[64]; /* Should be only 32 after successful decryption, but on failure might take up to 64 bytes. */ BYTE crypt_client_random[256 + 8]; @@ -332,7 +451,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) BYTE* mod; BYTE* priv_exp; - if (rdp->settings->DisableEncryption == FALSE) + if (!rdp->settings->DisableEncryption) { /* No RDP Security. */ return TRUE; @@ -353,10 +472,12 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) return FALSE; } - if(Stream_GetRemainingLength(s) < 4) + if (Stream_GetRemainingLength(s) < 4) return FALSE; + Stream_Read_UINT32(s, rand_len); - if(Stream_GetRemainingLength(s) < rand_len + 8) /* include 8 bytes of padding */ + + if (Stream_GetRemainingLength(s) < rand_len + 8) /* include 8 bytes of padding */ return FALSE; key_len = rdp->settings->RdpServerRsaKey->ModulusLength; @@ -367,7 +488,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) return FALSE; } - memset(crypt_client_random, 0, sizeof(crypt_client_random)); + ZeroMemory(crypt_client_random, sizeof(crypt_client_random)); Stream_Read(s, crypt_client_random, rand_len); /* 8 zero bytes of padding */ Stream_Seek(s, 8); @@ -382,6 +503,7 @@ static BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) } rdp->do_crypt = TRUE; + if (rdp->settings->SaltedChecksum) rdp->do_secure_checksum = TRUE; @@ -415,7 +537,7 @@ BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s) if (!mcs_send_attach_user_request(rdp->mcs)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER); return TRUE; } @@ -428,7 +550,7 @@ BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s) if (!mcs_send_channel_join_request(rdp->mcs, rdp->mcs->user_id)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN); return TRUE; } @@ -498,7 +620,7 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s) if (!rdp_send_client_info(rdp)) return FALSE; - rdp->state = CONNECTION_STATE_LICENSE; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_LICENSING); } return TRUE; @@ -517,7 +639,7 @@ BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s) if (rdp->license->state == LICENSE_STATE_COMPLETED) { - rdp->state = CONNECTION_STATE_CAPABILITY; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); } return TRUE; @@ -567,8 +689,7 @@ BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s) IFCALL(rdp->update->DesktopResize, rdp->update->context); } - rdp->state = CONNECTION_STATE_FINALIZATION; - update_reset_state(rdp->update); + rdp_client_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION); return rdp_client_connect_finalize(rdp); } @@ -583,18 +704,103 @@ BOOL rdp_client_connect_finalize(rdpRdp* rdp) if (!rdp_send_client_synchronize_pdu(rdp)) return FALSE; + if (!rdp_send_client_control_pdu(rdp, CTRLACTION_COOPERATE)) return FALSE; + if (!rdp_send_client_control_pdu(rdp, CTRLACTION_REQUEST_CONTROL)) return FALSE; - if (!rdp_send_client_persistent_key_list_pdu(rdp)) - return FALSE; + /** + * [MS-RDPBCGR] 2.2.1.17 + * Client persistent key list must be sent if a bitmap is + * stored in persistent bitmap cache or the server has advertised support for bitmap + * host cache and a deactivation reactivation sequence is *not* in progress. + */ + + if (!rdp->deactivation_reactivation && rdp->settings->BitmapCachePersistEnabled) + { + if (!rdp_send_client_persistent_key_list_pdu(rdp)) + return FALSE; + } + if (!rdp_send_client_font_list_pdu(rdp, FONTLIST_FIRST | FONTLIST_LAST)) return FALSE; return TRUE; } +int rdp_client_transition_to_state(rdpRdp* rdp, int state) +{ + int status = 0; + + switch (state) + { + case CONNECTION_STATE_INITIAL: + rdp->state = CONNECTION_STATE_INITIAL; + break; + + case CONNECTION_STATE_NEGO: + rdp->state = CONNECTION_STATE_NEGO; + break; + + case CONNECTION_STATE_MCS_CONNECT: + rdp->state = CONNECTION_STATE_MCS_CONNECT; + break; + + case CONNECTION_STATE_MCS_ERECT_DOMAIN: + rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + break; + + case CONNECTION_STATE_MCS_ATTACH_USER: + rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + break; + + case CONNECTION_STATE_MCS_CHANNEL_JOIN: + rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + break; + + case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: + rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT; + break; + + case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: + rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE; + break; + + case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT: + rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT; + break; + + case CONNECTION_STATE_LICENSING: + rdp->state = CONNECTION_STATE_LICENSING; + break; + + case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING: + rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING; + break; + + case CONNECTION_STATE_CAPABILITIES_EXCHANGE: + rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE; + break; + + case CONNECTION_STATE_FINALIZATION: + rdp->state = CONNECTION_STATE_FINALIZATION; + update_reset_state(rdp->update); + rdp->finalize_sc_pdus = 0; + break; + + case CONNECTION_STATE_ACTIVE: + rdp->state = CONNECTION_STATE_ACTIVE; + break; + + default: + status = -1; + break; + } + + return status; +} + BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) { BOOL status; @@ -609,8 +815,8 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) fprintf(stderr, "Client Security: NLA:%d TLS:%d RDP:%d\n", (rdp->nego->requested_protocols & PROTOCOL_NLA) ? 1 : 0, - (rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0, - (rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0); + (rdp->nego->requested_protocols & PROTOCOL_TLS) ? 1 : 0, + (rdp->nego->requested_protocols == PROTOCOL_RDP) ? 1: 0); fprintf(stderr, "Server Security: NLA:%d TLS:%d RDP:%d\n", settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity); @@ -634,13 +840,14 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) fprintf(stderr, "Negotiated Security: NLA:%d TLS:%d RDP:%d\n", (rdp->nego->selected_protocol & PROTOCOL_NLA) ? 1 : 0, - (rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0, - (rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0); + (rdp->nego->selected_protocol & PROTOCOL_TLS) ? 1 : 0, + (rdp->nego->selected_protocol == PROTOCOL_RDP) ? 1: 0); if (!nego_send_negotiation_response(rdp->nego)) return FALSE; status = FALSE; + if (rdp->nego->selected_protocol & PROTOCOL_NLA) status = transport_accept_nla(rdp->transport); else if (rdp->nego->selected_protocol & PROTOCOL_TLS) @@ -653,7 +860,7 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) transport_set_blocking_mode(rdp->transport, FALSE); - rdp->state = CONNECTION_STATE_NEGO; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_NEGO); return TRUE; } @@ -677,7 +884,7 @@ BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s) if (!mcs_send_connect_response(rdp->mcs)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_CONNECT; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_CONNECT); return TRUE; } @@ -687,7 +894,7 @@ BOOL rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, wStream* s) if (!mcs_recv_erect_domain_request(rdp->mcs, s)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ERECT_DOMAIN); return TRUE; } @@ -700,7 +907,7 @@ BOOL rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, wStream* s) if (!mcs_send_attach_user_confirm(rdp->mcs)) return FALSE; - rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER); return TRUE; } @@ -731,44 +938,23 @@ BOOL rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, wStream* s) all_joined = FALSE; } - if (rdp->mcs->user_channel_joined && rdp->mcs->global_channel_joined && all_joined) - rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; - - return TRUE; -} - -BOOL rdp_server_accept_client_keys(rdpRdp* rdp, wStream* s) -{ - - if (!rdp_server_establish_keys(rdp, s)) - return FALSE; - - rdp->state = CONNECTION_STATE_ESTABLISH_KEYS; - - return TRUE; -} - -BOOL rdp_server_accept_client_info(rdpRdp* rdp, wStream* s) -{ - - if (!rdp_recv_client_info(rdp, s)) - return FALSE; - - if (!license_send_valid_client_error_packet(rdp->license)) - return FALSE; - - rdp->state = CONNECTION_STATE_LICENSE; + if ((rdp->mcs->user_channel_joined) && (rdp->mcs->global_channel_joined) && all_joined) + { + rdp_server_transition_to_state(rdp, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT); + } return TRUE; } BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s) { + if (rdp->state != CONNECTION_STATE_CAPABILITIES_EXCHANGE) + return FALSE; + if (!rdp_recv_confirm_active(rdp, s)) return FALSE; - rdp->state = CONNECTION_STATE_ACTIVE; - update_reset_state(rdp->update); + rdp_server_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION); if (!rdp_send_server_synchronize_pdu(rdp)) return FALSE; @@ -784,7 +970,7 @@ BOOL rdp_server_reactivate(rdpRdp* rdp) if (!rdp_send_deactivate_all(rdp)) return FALSE; - rdp->state = CONNECTION_STATE_LICENSE; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); if (!rdp_send_demand_active(rdp)) return FALSE; @@ -792,3 +978,107 @@ BOOL rdp_server_reactivate(rdpRdp* rdp) return TRUE; } +int rdp_server_transition_to_state(rdpRdp* rdp, int state) +{ + int status = 0; + freerdp_peer* client = NULL; + + if (rdp->state >= CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT) + client = rdp->context->peer; + + if (rdp->state < CONNECTION_STATE_ACTIVE) + { + if (client) + client->activated = FALSE; + } + + switch (state) + { + case CONNECTION_STATE_INITIAL: + rdp->state = CONNECTION_STATE_INITIAL; + break; + + case CONNECTION_STATE_NEGO: + rdp->state = CONNECTION_STATE_NEGO; + break; + + case CONNECTION_STATE_MCS_CONNECT: + rdp->state = CONNECTION_STATE_MCS_CONNECT; + break; + + case CONNECTION_STATE_MCS_ERECT_DOMAIN: + rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + break; + + case CONNECTION_STATE_MCS_ATTACH_USER: + rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + break; + + case CONNECTION_STATE_MCS_CHANNEL_JOIN: + rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + break; + + case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: + rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT; + break; + + case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: + rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE; + break; + + case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT: + rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT; + break; + + case CONNECTION_STATE_LICENSING: + rdp->state = CONNECTION_STATE_LICENSING; + break; + + case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING: + rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING; + break; + + case CONNECTION_STATE_CAPABILITIES_EXCHANGE: + rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE; + rdp->AwaitCapabilities = FALSE; + break; + + case CONNECTION_STATE_FINALIZATION: + rdp->state = CONNECTION_STATE_FINALIZATION; + rdp->finalize_sc_pdus = 0; + break; + + case CONNECTION_STATE_ACTIVE: + rdp->state = CONNECTION_STATE_ACTIVE; + update_reset_state(rdp->update); + + if (client) + { + if (!client->connected) + { + /** + * PostConnect should only be called once and should not + * be called after a reactivation sequence. + */ + + IFCALLRET(client->PostConnect, client->connected, client); + + if (!client->connected) + return -1; + } + + IFCALLRET(client->Activate, client->activated, client); + + if (!client->activated) + return -1; + } + + break; + + default: + status = -1; + break; + } + + return status; +} diff --git a/libfreerdp/core/connection.h b/libfreerdp/core/connection.h index ec6f57415..b23e398cc 100644 --- a/libfreerdp/core/connection.h +++ b/libfreerdp/core/connection.h @@ -37,11 +37,14 @@ enum CONNECTION_STATE CONNECTION_STATE_MCS_ERECT_DOMAIN = 3, CONNECTION_STATE_MCS_ATTACH_USER = 4, CONNECTION_STATE_MCS_CHANNEL_JOIN = 5, - CONNECTION_STATE_ESTABLISH_KEYS = 6, - CONNECTION_STATE_LICENSE = 7, - CONNECTION_STATE_CAPABILITY = 8, - CONNECTION_STATE_FINALIZATION = 9, - CONNECTION_STATE_ACTIVE = 10 + CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT = 6, + CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE = 7, + CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT = 8, + CONNECTION_STATE_LICENSING = 9, + CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING = 10, + CONNECTION_STATE_CAPABILITIES_EXCHANGE = 11, + CONNECTION_STATE_FINALIZATION = 12, + CONNECTION_STATE_ACTIVE = 13 }; BOOL rdp_client_connect(rdpRdp* rdp); @@ -52,15 +55,16 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_finalize(rdpRdp* rdp); +int rdp_client_transition_to_state(rdpRdp* rdp, int state); BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, wStream* s); -BOOL rdp_server_accept_client_keys(rdpRdp* rdp, wStream* s); -BOOL rdp_server_accept_client_info(rdpRdp* rdp, wStream* s); BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s); +BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s); BOOL rdp_server_reactivate(rdpRdp* rdp); +int rdp_server_transition_to_state(rdpRdp* rdp, int state); #endif /* __CONNECTION_H */ diff --git a/libfreerdp/core/errinfo.c b/libfreerdp/core/errinfo.c index 2b78dbc51..da028318a 100644 --- a/libfreerdp/core/errinfo.c +++ b/libfreerdp/core/errinfo.c @@ -443,6 +443,44 @@ static const ERRINFO ERRINFO_CODES[] = ERRINFO_DEFINE(NONE) }; +const char* freerdp_get_error_info_string(UINT32 code) +{ + const ERRINFO* errInfo; + + errInfo = &ERRINFO_CODES[0]; + + while (errInfo->code != ERRINFO_NONE) + { + if (code == errInfo->code) + { + return errInfo->info; + } + + errInfo++; + } + + return "Unknown error."; +} + +const char* freerdp_get_error_info_name(UINT32 code) +{ + const ERRINFO* errInfo; + + errInfo = &ERRINFO_CODES[0]; + + while (errInfo->code != ERRINFO_NONE) + { + if (code == errInfo->code) + { + return errInfo->name; + } + + errInfo++; + } + + return "ERRINFO_UNKNOWN"; +} + void rdp_print_errinfo(UINT32 code) { const ERRINFO* errInfo; diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index b8569fc61..67106c7b7 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -178,7 +178,7 @@ static BOOL fastpath_recv_update_common(rdpFastPath* fastpath, wStream* s) switch (updateType) { case UPDATE_TYPE_BITMAP: - if (!update_read_bitmap(update, s, &update->bitmap_update)) + if (!update_read_bitmap_update(update, s, &update->bitmap_update)) return FALSE; IFCALL(update->BitmapUpdate, context, &update->bitmap_update); break; @@ -209,7 +209,7 @@ static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32 s #ifdef WITH_DEBUG_RDP DEBUG_RDP("recv Fast-Path %s Update (0x%X), length:%d", - updateCode < ARRAYSIZE(FASTPATH_UPDATETYPE_STRINGS) ? FASTPATH_UPDATETYPE_STRINGS[updateCode] : "???", updateCode, capacity); + updateCode < ARRAYSIZE(FASTPATH_UPDATETYPE_STRINGS) ? FASTPATH_UPDATETYPE_STRINGS[updateCode] : "???", updateCode, size); #endif switch (updateCode) @@ -856,6 +856,8 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s comp_flags = FASTPATH_OUTPUT_COMPRESSION_USED; header_bytes = 7 + sec_bytes; bm = (BYTE*) (rdp->mppc_enc->outputBuffer - header_bytes); + if (comp_update) + Stream_Free(comp_update, FALSE); comp_update = Stream_New(bm, pdu_data_bytes + header_bytes); ls = comp_update; } @@ -902,6 +904,8 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s Stream_Write_UINT16(ls, pdu_data_bytes); + if (update) + Stream_Free(update, FALSE); update = Stream_New(bm, pduLength); Stream_Seek(update, pduLength); diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 3c77b8e05..b447a8477 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -31,6 +31,7 @@ #include "message.h" #include +#include #include #include @@ -55,6 +56,7 @@ BOOL freerdp_connect(freerdp* instance) rdpRdp* rdp; rdpSettings* settings; BOOL status = FALSE; + ConnectionResultEventArgs e; /* We always set the return code to 0 before we start the connect sequence*/ connectErrorCode = 0; @@ -81,7 +83,8 @@ BOOL freerdp_connect(freerdp* instance) connectErrorCode = PREECONNECTERROR; } fprintf(stderr, "%s:%d: freerdp_pre_connect failed\n", __FILE__, __LINE__); - return FALSE; + + goto freerdp_connect_finally; } status = rdp_client_connect(rdp); @@ -90,7 +93,7 @@ BOOL freerdp_connect(freerdp* instance) if (instance->settings->AuthenticationOnly) { fprintf(stderr, "%s:%d: Authentication only, exit status %d\n", __FILE__, __LINE__, !status); - return status; + goto freerdp_connect_finally; } if (status) @@ -116,7 +119,7 @@ BOOL freerdp_connect(freerdp* instance) connectErrorCode = POSTCONNECTERROR; } - return FALSE; + goto freerdp_connect_finally; } if (instance->settings->PlayRemoteFx) @@ -127,30 +130,38 @@ BOOL freerdp_connect(freerdp* instance) update = instance->update; - s = StreamPool_Take(rdp->transport->ReceivePool, 0); - instance->update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE); + update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE); - if (update->pcap_rfx) - update->play_rfx = TRUE; - - while (update->play_rfx && pcap_has_next_record(update->pcap_rfx)) + if (!update->pcap_rfx) { + status = FALSE; + goto freerdp_connect_finally; + } + else + { + update->play_rfx = TRUE; + } + + while (pcap_has_next_record(update->pcap_rfx)) + { + pcap_get_next_record_header(update->pcap_rfx, &record); - Stream_EnsureCapacity(s, record.length); + s = StreamPool_Take(rdp->transport->ReceivePool, record.length); record.data = Stream_Buffer(s); pcap_get_next_record_content(update->pcap_rfx, &record); + Stream_SetLength(s,record.length); Stream_SetPosition(s, 0); update->BeginPaint(update->context); - update_recv_surfcmds(update, Stream_Capacity(s), s); + update_recv_surfcmds(update, Stream_Length(s) , s); update->EndPaint(update->context); + Stream_Release(s); } - Stream_Release(s); - - return TRUE; + status = TRUE; + goto freerdp_connect_finally; } } @@ -166,6 +177,12 @@ BOOL freerdp_connect(freerdp* instance) SetEvent(rdp->transport->connectedEvent); + freerdp_connect_finally: + + EventArgsInit(&e, "freerdp"); + e.result = status ? 0 : -1; + PubSub_OnConnectionResult(instance->context->pubSub, instance->context, &e); + return status; } @@ -320,12 +337,18 @@ void freerdp_get_version(int* major, int* minor, int* revision) static wEventType FreeRDP_Events[] = { - DEFINE_EVENT_ENTRY(WindowStateChange) - DEFINE_EVENT_ENTRY(ResizeWindow) - DEFINE_EVENT_ENTRY(EmbedWindow) - DEFINE_EVENT_ENTRY(ErrorInfo) - DEFINE_EVENT_ENTRY(ParamChange) - DEFINE_EVENT_ENTRY(Terminate) + DEFINE_EVENT_ENTRY(WindowStateChange) + DEFINE_EVENT_ENTRY(ResizeWindow) + DEFINE_EVENT_ENTRY(LocalResizeWindow) + DEFINE_EVENT_ENTRY(EmbedWindow) + DEFINE_EVENT_ENTRY(PanningChange) + DEFINE_EVENT_ENTRY(ScalingFactorChange) + DEFINE_EVENT_ENTRY(ErrorInfo) + DEFINE_EVENT_ENTRY(ParamChange) + DEFINE_EVENT_ENTRY(Terminate) + DEFINE_EVENT_ENTRY(ConnectionResult) + DEFINE_EVENT_ENTRY(ChannelConnected) + DEFINE_EVENT_ENTRY(ChannelDisconnected) }; /** Allocator function for a rdp context. @@ -343,18 +366,19 @@ int freerdp_context_new(freerdp* instance) instance->context = (rdpContext*) malloc(instance->ContextSize); ZeroMemory(instance->context, instance->ContextSize); + context = instance->context; + context->instance = instance; context->pubSub = PubSub_New(TRUE); PubSub_AddEventTypes(context->pubSub, FreeRDP_Events, sizeof(FreeRDP_Events) / sizeof(wEventType)); - rdp = rdp_new(instance); + rdp = rdp_new(context); instance->input = rdp->input; instance->update = rdp->update; instance->settings = rdp->settings; context->graphics = graphics_new(context); - context->instance = instance; context->rdp = rdp; context->input = instance->input; @@ -392,7 +416,10 @@ void freerdp_context_free(freerdp* instance) 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); diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index c6bb45dd1..cf013f2d8 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -1369,6 +1369,10 @@ BOOL tsg_disconnect(rdpTsg* tsg) * | | */ + + if (tsg == NULL) + return FALSE; + tsg->rpc->client->SynchronousReceive = TRUE; /* if we are already in state pending (i.e. if a server initiated disconnect was issued) @@ -1392,7 +1396,12 @@ BOOL tsg_disconnect(rdpTsg* tsg) int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) { int CopyLength; - rdpRpc* rpc = tsg->rpc; + rdpRpc* rpc; + + if (tsg == NULL) + return -1; + + rpc = tsg->rpc; if (tsg->PendingPdu) { diff --git a/libfreerdp/core/graphics.c b/libfreerdp/core/graphics.c index 18b6d05cb..218f10c60 100644 --- a/libfreerdp/core/graphics.c +++ b/libfreerdp/core/graphics.c @@ -117,10 +117,16 @@ void Pointer_Free(rdpContext* context, rdpPointer* pointer) pointer->Free(context, pointer); if (pointer->xorMaskData) + { free(pointer->xorMaskData); + pointer->xorMaskData = NULL; + } if (pointer->andMaskData) + { free(pointer->andMaskData); + pointer->andMaskData = NULL; + } free(pointer); } diff --git a/libfreerdp/core/input.c b/libfreerdp/core/input.c index 848a66505..64011b807 100644 --- a/libfreerdp/core/input.c +++ b/libfreerdp/core/input.c @@ -495,6 +495,8 @@ rdpInput* input_new(rdpRdp* rdp) if (input != NULL) { ZeroMemory(input, sizeof(rdpInput)); + + input->queue = MessageQueue_New(); } return input; @@ -507,6 +509,8 @@ void input_free(rdpInput* input) if (input->asynchronous) input_message_proxy_free(input->proxy); + MessageQueue_Free(input->queue); + free(input); } } diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c index b98d41e9a..ebc462fa5 100644 --- a/libfreerdp/core/license.c +++ b/libfreerdp/core/license.c @@ -107,7 +107,7 @@ void license_print_scope_list(SCOPE_LIST* scopeList) for (index = 0; index < scopeList->count; index++) { scope = &scopeList->array[index]; - fprintf(stderr, "\t%s\n", (char*) scope->buffer); + fprintf(stderr, "\t%s\n", (char*) scope->data); } } @@ -810,11 +810,11 @@ BOOL license_read_platform_challenge_packet(rdpLicense* license, wStream* s) fprintf(stderr, "\n"); fprintf(stderr, "EncryptedPlatformChallenge:\n"); - winpr_HexDump(license->EncryptedPlatformChallenge->buffer, license->EncryptedPlatformChallenge->length); + winpr_HexDump(license->EncryptedPlatformChallenge->data, license->EncryptedPlatformChallenge->length); fprintf(stderr, "\n"); fprintf(stderr, "PlatformChallenge:\n"); - winpr_HexDump(license->PlatformChallenge->buffer, license->PlatformChallenge->length); + winpr_HexDump(license->PlatformChallenge->data, license->PlatformChallenge->length); fprintf(stderr, "\n"); fprintf(stderr, "MacData:\n"); @@ -937,13 +937,13 @@ void license_write_new_license_request_packet(rdpLicense* license, wStream* s) fprintf(stderr, "\n"); fprintf(stderr, "EncryptedPremasterSecret\n"); - winpr_HexDump(license->EncryptedPremasterSecret->buffer, license->EncryptedPremasterSecret->length); + winpr_HexDump(license->EncryptedPremasterSecret->data, license->EncryptedPremasterSecret->length); fprintf(stderr, "\n"); - fprintf(stderr, "ClientUserName (%d): %s\n", license->ClientUserName->length, (char*) license->ClientUserName->buffer); + fprintf(stderr, "ClientUserName (%d): %s\n", license->ClientUserName->length, (char*) license->ClientUserName->data); fprintf(stderr, "\n"); - fprintf(stderr, "ClientMachineName (%d): %s\n", license->ClientMachineName->length, (char*) license->ClientMachineName->buffer); + fprintf(stderr, "ClientMachineName (%d): %s\n", license->ClientMachineName->length, (char*) license->ClientMachineName->data); fprintf(stderr, "\n"); #endif } @@ -1048,7 +1048,7 @@ void license_send_platform_challenge_response_packet(rdpLicense* license) fprintf(stderr, "\n"); fprintf(stderr, "EncryptedHardwareId:\n"); - winpr_HexDump(license->EncryptedHardwareId->buffer, 20); + winpr_HexDump(license->EncryptedHardwareId->data, 20); fprintf(stderr, "\n"); #endif diff --git a/libfreerdp/core/listener.c b/libfreerdp/core/listener.c index 2390542fb..fb49bf3d4 100644 --- a/libfreerdp/core/listener.c +++ b/libfreerdp/core/listener.c @@ -156,7 +156,9 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a continue; } - listener->sockfds[listener->num_sockfds++] = sockfd; + listener->sockfds[listener->num_sockfds] = sockfd; + listener->events[listener->num_sockfds] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd); + listener->num_sockfds++; if (ai->ai_family == AF_INET) sin_addr = &(((struct sockaddr_in*) ai->ai_addr)->sin_addr); @@ -211,7 +213,9 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* return FALSE; } - listener->sockfds[listener->num_sockfds++] = sockfd; + listener->sockfds[listener->num_sockfds] = sockfd; + listener->events[listener->num_sockfds] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd); + listener->num_sockfds++; fprintf(stderr, "Listening on socket %s.\n", addr.sun_path); @@ -230,6 +234,7 @@ static void freerdp_listener_close(freerdp_listener* instance) for (i = 0; i < listener->num_sockfds; i++) { close(listener->sockfds[i]); + CloseHandle(listener->events[i]); } listener->num_sockfds = 0; @@ -237,21 +242,38 @@ static void freerdp_listener_close(freerdp_listener* instance) static BOOL freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount) { - int i; + int index; rdpListener* listener = (rdpListener*) instance->listener; if (listener->num_sockfds < 1) return FALSE; - for (i = 0; i < listener->num_sockfds; i++) + for (index = 0; index < listener->num_sockfds; index++) { - rfds[*rcount] = (void*)(long)(listener->sockfds[i]); + rfds[*rcount] = (void*)(long)(listener->sockfds[index]); (*rcount)++; } return TRUE; } +int freerdp_listener_get_event_handles(freerdp_listener* instance, HANDLE* events, DWORD* nCount) +{ + int index; + rdpListener* listener = (rdpListener*) instance->listener; + + if (listener->num_sockfds < 1) + return -1; + + for (index = 0; index < listener->num_sockfds; index++) + { + events[*nCount] = listener->events[index]; + (*nCount)++; + } + + return 0; +} + static BOOL freerdp_listener_check_fds(freerdp_listener* instance) { int i; @@ -327,6 +349,7 @@ freerdp_listener* freerdp_listener_new(void) instance->Open = freerdp_listener_open; instance->OpenLocal = freerdp_listener_open_local; instance->GetFileDescriptor = freerdp_listener_get_fds; + instance->GetEventHandles = freerdp_listener_get_event_handles; instance->CheckFileDescriptor = freerdp_listener_check_fds; instance->Close = freerdp_listener_close; diff --git a/libfreerdp/core/listener.h b/libfreerdp/core/listener.h index 51aa569e0..1474bf7db 100644 --- a/libfreerdp/core/listener.h +++ b/libfreerdp/core/listener.h @@ -23,14 +23,21 @@ typedef struct rdp_listener rdpListener; #include "rdp.h" + +#include +#include + #include +#define MAX_LISTENER_HANDLES 5 + struct rdp_listener { freerdp_listener* instance; - int sockfds[5]; int num_sockfds; + int sockfds[MAX_LISTENER_HANDLES]; + HANDLE events[MAX_LISTENER_HANDLES]; }; #endif diff --git a/libfreerdp/core/mcs.c b/libfreerdp/core/mcs.c index d5ea0899b..43a7a480c 100644 --- a/libfreerdp/core/mcs.c +++ b/libfreerdp/core/mcs.c @@ -356,15 +356,15 @@ BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s) return FALSE; /* targetParameters (DomainParameters) */ - if(!mcs_read_domain_parameters(s, &mcs->targetParameters)) + if (!mcs_read_domain_parameters(s, &mcs->targetParameters)) return FALSE; /* minimumParameters (DomainParameters) */ - if(!mcs_read_domain_parameters(s, &mcs->minimumParameters)) + if (!mcs_read_domain_parameters(s, &mcs->minimumParameters)) return FALSE; /* maximumParameters (DomainParameters) */ - if(!mcs_read_domain_parameters(s, &mcs->maximumParameters)) + if (!mcs_read_domain_parameters(s, &mcs->maximumParameters)) return FALSE; if (!ber_read_octet_string_tag(s, &length) || Stream_GetRemainingLength(s) < length) @@ -510,7 +510,7 @@ BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s) if (!tpdu_read_data(s, &li)) return FALSE; - if(!ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length) || + if (!ber_read_application_tag(s, MCS_TYPE_CONNECT_RESPONSE, &length) || !ber_read_enumerated(s, &result, MCS_Result_enum_length) || !ber_read_integer(s, &calledConnectId) || !mcs_read_domain_parameters(s, &(mcs->domainParameters)) || diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c index 720b13797..f772e65fd 100644 --- a/libfreerdp/core/message.c +++ b/libfreerdp/core/message.c @@ -1741,7 +1741,6 @@ rdpUpdateProxy* update_message_proxy_new(rdpUpdate* update) ZeroMemory(message, sizeof(rdpUpdateProxy)); message->update = update; - update->queue = MessageQueue_New(); update_message_register_interface(message, update); } @@ -1752,7 +1751,6 @@ void update_message_proxy_free(rdpUpdateProxy* message) { if (message) { - MessageQueue_Free(message->update->queue); free(message); } } @@ -1940,7 +1938,6 @@ rdpInputProxy* input_message_proxy_new(rdpInput* input) ZeroMemory(proxy, sizeof(rdpInputProxy)); proxy->input = input; - input->queue = MessageQueue_New(); input_message_proxy_register(proxy, input); } @@ -1951,7 +1948,6 @@ void input_message_proxy_free(rdpInputProxy* proxy) { if (proxy) { - MessageQueue_Free(proxy->input->queue); free(proxy); } } diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 2b4b71992..875c0ae73 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -1245,6 +1245,7 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings* ZeroMemory(&credssp->negoToken, sizeof(SecBuffer)); ZeroMemory(&credssp->pubKeyAuth, sizeof(SecBuffer)); ZeroMemory(&credssp->authInfo, sizeof(SecBuffer)); + SecInvalidateHandle(&credssp->context); if (credssp->server) { diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index e5cc520b7..d0f5c9713 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -1364,7 +1364,7 @@ BOOL update_read_memblt_order(wStream* s, ORDER_INFO* orderInfo, MEMBLT_ORDER* m int update_approximate_memblt_order(ORDER_INFO* orderInfo, MEMBLT_ORDER* memblt) { - return 32; + return 64; } BOOL update_write_memblt_order(wStream* s, ORDER_INFO* orderInfo, MEMBLT_ORDER* memblt) @@ -2600,7 +2600,7 @@ BOOL update_read_create_offscreen_bitmap_order(wStream* s, CREATE_OFFSCREEN_BITM int update_approximate_create_offscreen_bitmap_order(CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap) { OFFSCREEN_DELETE_LIST* deleteList = &(create_offscreen_bitmap->deleteList); - return 8 + deleteList->cIndices * 2; + return 32 + deleteList->cIndices * 2; } BOOL update_write_create_offscreen_bitmap_order(wStream* s, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap) diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index 3806a736e..5b38c905e 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -23,6 +23,7 @@ #include +#include "info.h" #include "certificate.h" #include @@ -53,6 +54,11 @@ static BOOL freerdp_peer_get_fds(freerdp_peer* client, void** rfds, int* rcount) return TRUE; } +static HANDLE freerdp_peer_get_event_handle(freerdp_peer* client) +{ + return client->context->rdp->transport->TcpIn->event; +} + static BOOL freerdp_peer_check_fds(freerdp_peer* client) { int status; @@ -105,29 +111,6 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s) if (!rdp_server_accept_client_font_list_pdu(client->context->rdp, s)) return FALSE; - if (!client->connected) - { - /** - * PostConnect should only be called once and should not be called - * after a reactivation sequence. - */ - - IFCALLRET(client->PostConnect, client->connected, client); - - if (!client->connected) - return FALSE; - } - - if (!client->activated) - { - /* Activate will be called everytime after the client is activated/reactivated. */ - - IFCALLRET(client->Activate, client->activated, client); - - if (!client->activated) - return FALSE; - } - break; case DATA_PDU_TYPE_SHUTDOWN_REQUEST: @@ -135,7 +118,7 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s) return FALSE; case DATA_PDU_TYPE_FRAME_ACKNOWLEDGE: - if(Stream_GetRemainingLength(s) < 4) + if (Stream_GetRemainingLength(s) < 4) return FALSE; Stream_Read_UINT32(s, client->ack_frame_id); IFCALL(client->update->SurfaceFrameAcknowledge, client->update->context, client->ack_frame_id); @@ -194,7 +177,7 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) if (channelId != MCS_GLOBAL_CHANNEL_ID) { - if(!freerdp_channel_peer_process(client, s, channelId)) + if (!freerdp_channel_peer_process(client, s, channelId)) return -1; } else @@ -211,6 +194,11 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) return -1; break; + case PDU_TYPE_CONFIRM_ACTIVE: + if (!rdp_server_accept_confirm_active(rdp, s)) + return -1; + break; + default: fprintf(stderr, "Client sent pduType %d\n", pduType); return -1; @@ -228,8 +216,6 @@ static int peer_recv_fastpath_pdu(freerdp_peer* client, wStream* s) rdp = client->context->rdp; fastpath = rdp->fastpath; - //if (!fastpath_read_header_rdp(fastpath, s, &length)) - // return -1; fastpath_read_header_rdp(fastpath, s, &length); @@ -272,6 +258,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) sspi_CopyAuthIdentity(&client->identity, &(rdp->nego->transport->credssp->identity)); IFCALLRET(client->Logon, client->authenticated, client, &client->identity, TRUE); credssp_free(rdp->nego->transport->credssp); + rdp->nego->transport->credssp = NULL; } else { @@ -300,36 +287,71 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) return -1; break; - case CONNECTION_STATE_MCS_CHANNEL_JOIN: + case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: if (rdp->settings->DisableEncryption) { - if (!rdp_server_accept_client_keys(rdp, s)) + if (!rdp_server_establish_keys(rdp, s)) return -1; - break; } - rdp->state = CONNECTION_STATE_ESTABLISH_KEYS; - /* FALLTHROUGH */ - case CONNECTION_STATE_ESTABLISH_KEYS: - if (!rdp_server_accept_client_info(rdp, s)) - return -1; + rdp_server_transition_to_state(rdp, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE); + return peer_recv_callback(transport, s, extra); - IFCALL(client->Capabilities, client); - - if (!rdp_send_demand_active(rdp)) - return -1; break; - case CONNECTION_STATE_LICENSE: - if (!rdp_server_accept_confirm_active(rdp, s)) + case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: + + if (!rdp_recv_client_info(rdp, s)) + return -1; + + rdp_server_transition_to_state(rdp, CONNECTION_STATE_LICENSING); + return peer_recv_callback(transport, NULL, extra); + + break; + + case CONNECTION_STATE_LICENSING: + + if (!license_send_valid_client_error_packet(rdp->license)) + return FALSE; + + rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); + return peer_recv_callback(transport, NULL, extra); + + break; + + case CONNECTION_STATE_CAPABILITIES_EXCHANGE: + + if (!rdp->AwaitCapabilities) + { + IFCALL(client->Capabilities, client); + + if (!rdp_send_demand_active(rdp)) + return -1; + + rdp->AwaitCapabilities = TRUE; + + if (s) + { + if (peer_recv_pdu(client, s) < 0) + return -1; + } + } + else { /** * During reactivation sequence the client might sent some input or channel data * before receiving the Deactivate All PDU. We need to process them as usual. */ - Stream_SetPosition(s, 0); - return peer_recv_pdu(client, s); + + if (peer_recv_pdu(client, s) < 0) + return -1; } + + break; + + case CONNECTION_STATE_FINALIZATION: + if (peer_recv_pdu(client, s) < 0) + return -1; break; case CONNECTION_STATE_ACTIVE: @@ -354,6 +376,7 @@ static BOOL freerdp_peer_close(freerdp_peer* client) */ if (!rdp_send_deactivate_all(client->context->rdp)) return FALSE; + return mcs_send_disconnect_provider_ultimatum(client->context->rdp->mcs); } @@ -371,14 +394,15 @@ void freerdp_peer_context_new(freerdp_peer* client) { rdpRdp* rdp; - rdp = rdp_new(NULL); + client->context = (rdpContext*) malloc(client->ContextSize); + ZeroMemory(client->context, client->ContextSize); + + rdp = rdp_new(client->context); + client->input = rdp->input; client->update = rdp->update; client->settings = rdp->settings; - client->context = (rdpContext*) malloc(client->ContextSize); - ZeroMemory(client->context, client->ContextSize); - client->context->rdp = rdp; client->context->peer = client; client->context->input = client->input; @@ -413,12 +437,13 @@ freerdp_peer* freerdp_peer_new(int sockfd) freerdp_tcp_set_no_delay(sockfd, TRUE); - if (client != NULL) + if (client) { client->sockfd = sockfd; client->ContextSize = sizeof(rdpContext); client->Initialize = freerdp_peer_initialize; client->GetFileDescriptor = freerdp_peer_get_fds; + client->GetEventHandle = freerdp_peer_get_event_handle; client->CheckFileDescriptor = freerdp_peer_check_fds; client->Close = freerdp_peer_close; client->Disconnect = freerdp_peer_disconnect; diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 1a4704d3c..867fd5c1b 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -236,8 +236,9 @@ wStream* rdp_data_pdu_init(rdpRdp* rdp) * @param channel_id channel id */ -BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id) +BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) { + BYTE byte; UINT16 initiator; enum DomainMCSPDU MCSPDU; @@ -274,8 +275,8 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id return FALSE; per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */ - per_read_integer16(s, channel_id, 0); /* channelId */ - Stream_Seek(s, 1); /* dataPriority + Segmentation (0x70) */ + per_read_integer16(s, channelId, 0); /* channelId */ + Stream_Read_UINT8(s, byte); /* dataPriority + Segmentation (0x70) */ if (!per_read_length(s, length)) /* userData (OCTET_STRING) */ return FALSE; @@ -294,7 +295,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channel_id * @param channel_id channel id */ -void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channel_id) +void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channelId) { int body_length; enum DomainMCSPDU MCSPDU; @@ -314,10 +315,10 @@ void rdp_write_header(rdpRdp* rdp, wStream* s, UINT16 length, UINT16 channel_id) mcs_write_domain_mcspdu_header(s, MCSPDU, length, 0); per_write_integer16(s, rdp->mcs->user_id, MCS_BASE_CHANNEL_ID); /* initiator */ - per_write_integer16(s, channel_id, 0); /* channelId */ + per_write_integer16(s, channelId, 0); /* channelId */ Stream_Write_UINT8(s, 0x70); /* dataPriority + segmentation */ /* - * We always encode length in two bytes, eventhough we could use + * We always encode length in two bytes, even though we could use * only one byte if length <= 0x7F. It is just easier that way, * because we can leave room for fixed-length header, store all * the data first and then store the header. @@ -926,20 +927,21 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) status = -1; break; - case CONNECTION_STATE_LICENSE: + case CONNECTION_STATE_LICENSING: if (!rdp_client_connect_license(rdp, s)) status = -1; break; - case CONNECTION_STATE_CAPABILITY: + case CONNECTION_STATE_CAPABILITIES_EXCHANGE: if (!rdp_client_connect_demand_active(rdp, s)) status = -1; break; case CONNECTION_STATE_FINALIZATION: status = rdp_recv_pdu(rdp, s); + if ((status >= 0) && (rdp->finalize_sc_pdus == FINALIZE_SC_COMPLETE)) - rdp->state = CONNECTION_STATE_ACTIVE; + rdp_client_transition_to_state(rdp, CONNECTION_STATE_ACTIVE); break; case CONNECTION_STATE_ACTIVE: @@ -982,23 +984,25 @@ int rdp_check_fds(rdpRdp* rdp) * @return new RDP module */ -rdpRdp* rdp_new(freerdp* instance) +rdpRdp* rdp_new(rdpContext* context) { rdpRdp* rdp; rdp = (rdpRdp*) malloc(sizeof(rdpRdp)); - if (rdp != NULL) + if (rdp) { ZeroMemory(rdp, sizeof(rdpRdp)); - rdp->instance = instance; - rdp->settings = freerdp_settings_new((void*) instance); + rdp->context = context; - if (instance != NULL) - instance->settings = rdp->settings; + rdp->instance = context->instance; + rdp->settings = freerdp_settings_new((void*) context->instance); - rdp->extension = extension_new(instance); + if (context->instance) + context->instance->settings = rdp->settings; + + rdp->extension = extension_new(context->instance); rdp->transport = transport_new(rdp->settings); rdp->license = license_new(rdp); rdp->input = input_new(rdp); diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index a0f2c9530..aa43b988f 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -120,6 +120,7 @@ struct rdp_rdp { int state; freerdp* instance; + rdpContext* context; struct rdp_mcs* mcs; struct rdp_nego* nego; struct rdp_input* input; @@ -157,6 +158,8 @@ struct rdp_rdp UINT32 finalize_sc_pdus; BOOL disconnect; BOOL resendFocus; + BOOL deactivation_reactivation; + BOOL AwaitCapabilities; }; BOOL rdp_read_security_header(wStream* s, UINT16* flags); @@ -192,7 +195,7 @@ BOOL rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s); void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking); int rdp_check_fds(rdpRdp* rdp); -rdpRdp* rdp_new(freerdp* instance); +rdpRdp* rdp_new(rdpContext* context); void rdp_free(rdpRdp* rdp); #ifdef WITH_DEBUG_RDP diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index a02c80c7b..aaaaf99e9 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -334,6 +334,8 @@ rdpSettings* freerdp_settings_new(void* instance) settings->BitmapCacheV2CellInfo[4].numEntries = 2048; settings->BitmapCacheV2CellInfo[4].persistent = FALSE; + settings->NoBitmapCompressionHeader = TRUE; + settings->RefreshRect = TRUE; settings->SuppressOutput = TRUE; diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c index 3de41339f..7d0fb229a 100644 --- a/libfreerdp/core/surface.c +++ b/libfreerdp/core/surface.c @@ -58,15 +58,6 @@ static int update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT3 return 0; } -static void update_send_frame_acknowledge(rdpRdp* rdp, UINT32 frameId) -{ - wStream* s; - - s = rdp_data_pdu_init(rdp); - Stream_Write_UINT32(s, frameId); - rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FRAME_ACKNOWLEDGE, rdp->mcs->user_id); -} - static int update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s, UINT32 *length) { SURFACE_FRAME_MARKER* marker = &update->surface_frame_marker; @@ -79,13 +70,6 @@ static int update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s, UINT3 IFCALL(update->SurfaceFrameMarker, update->context, marker); - if (update->context->rdp->settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE] && - (update->context->rdp->settings->FrameAcknowledge > 0) && - (marker->frameAction == SURFACECMD_FRAMEACTION_END)) - { - update_send_frame_acknowledge(update->context->rdp, marker->frameId); - } - *length = 6; return 0; diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index a0ad86406..908e06ae3 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -253,6 +253,13 @@ BOOL tcp_set_keep_alive_mode(rdpTcp* tcp) return TRUE; } +int tcp_attach(rdpTcp* tcp, int sockfd) +{ + tcp->sockfd = sockfd; + SetEventFileDescriptor(tcp->event, tcp->sockfd); + return 0; +} + HANDLE tcp_get_event_handle(rdpTcp* tcp) { #ifndef _WIN32 diff --git a/libfreerdp/core/tcp.h b/libfreerdp/core/tcp.h index 539d77673..c22e5da05 100644 --- a/libfreerdp/core/tcp.h +++ b/libfreerdp/core/tcp.h @@ -56,6 +56,7 @@ int tcp_wait_read(rdpTcp* tcp); int tcp_wait_write(rdpTcp* tcp); BOOL tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking); BOOL tcp_set_keep_alive_mode(rdpTcp* tcp); +int tcp_attach(rdpTcp* tcp, int sockfd); HANDLE tcp_get_event_handle(rdpTcp* tcp); rdpTcp* tcp_new(rdpSettings* settings); diff --git a/libfreerdp/core/tpdu.c b/libfreerdp/core/tpdu.c index a701c11d7..30a649c22 100644 --- a/libfreerdp/core/tpdu.c +++ b/libfreerdp/core/tpdu.c @@ -22,6 +22,7 @@ #endif #include +#include #include "tpdu.h" @@ -66,9 +67,9 @@ * @return TPDU length indicator (LI) */ -BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE *li) +BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE* li) { - if(Stream_GetRemainingLength(s) < 3) + if (Stream_GetRemainingLength(s) < 3) return FALSE; Stream_Read_UINT8(s, *li); /* LI */ @@ -86,6 +87,7 @@ BOOL tpdu_read_header(wStream* s, BYTE* code, BYTE *li) /* Class 0 (1 byte) */ return Stream_SafeSeek(s, 5); } + return TRUE; } @@ -205,16 +207,18 @@ void tpdu_write_data(wStream* s) * @param s stream */ -BOOL tpdu_read_data(wStream* s, UINT16 *LI) +BOOL tpdu_read_data(wStream* s, UINT16* LI) { BYTE code; BYTE li; - if(!tpdu_read_header(s, &code, &li)) + if (!tpdu_read_header(s, &code, &li)) return FALSE; if (code != X224_TPDU_DATA) return FALSE; + *LI = li; + return TRUE; } diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index a9a710511..9aa30fd71 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -64,8 +64,7 @@ wStream* transport_send_stream_init(rdpTransport* transport, int size) void transport_attach(rdpTransport* transport, int sockfd) { - transport->TcpIn->sockfd = sockfd; - + tcp_attach(transport->TcpIn, sockfd); transport->SplitInputOutput = FALSE; transport->TcpOut = transport->TcpIn; } @@ -159,6 +158,7 @@ BOOL transport_connect_nla(rdpTransport* transport) "If credentials are valid, the NTLMSSP implementation may be to blame.\n"); credssp_free(transport->credssp); + transport->credssp = NULL; return FALSE; } @@ -212,7 +212,7 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por (LPTHREAD_START_ROUTINE) transport_client_thread, transport, 0, NULL); } - if (transport->settings->GatewayUsageMethod) + if (transport->settings->GatewayEnabled) { transport->layer = TRANSPORT_LAYER_TSG; transport->TcpOut = tcp_new(settings); @@ -292,6 +292,7 @@ BOOL transport_accept_nla(rdpTransport* transport) { fprintf(stderr, "client authentication failure\n"); credssp_free(transport->credssp); + transport->credssp = NULL; return FALSE; } @@ -738,7 +739,11 @@ int transport_check_fds(rdpTransport** ptransport) recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); - Stream_Release(received); + if (transport == *ptransport) + /* transport might now have been freed by rdp_client_redirect and a new rdp->transport created */ + /* so only release if still valid */ + Stream_Release(received); + if (recv_status < 0) status = -1; @@ -786,7 +791,6 @@ static void* transport_client_thread(void* arg) freerdp* instance; rdpContext* context; rdpTransport* transport; - TerminateEventArgs e; transport = (rdpTransport*) arg; instance = (freerdp*) transport->settings->instance; diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index 6b24f178b..bf6829174 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -33,15 +34,13 @@ #include #include -/* -static const char* const UPDATE_TYPE_STRINGS[] = +const char* const UPDATE_TYPE_STRINGS[] = { "Orders", "Bitmap", "Palette", "Synchronize" }; -*/ extern const BYTE PRIMARY_DRAWING_ORDER_FIELD_BYTES[]; @@ -67,80 +66,148 @@ BOOL update_recv_orders(rdpUpdate* update, wStream* s) return TRUE; } -BOOL update_read_bitmap_data(wStream* s, BITMAP_DATA* bitmap_data) +BOOL update_read_bitmap_data(rdpUpdate* update, wStream* s, BITMAP_DATA* bitmapData) { if (Stream_GetRemainingLength(s) < 18) return FALSE; - Stream_Read_UINT16(s, bitmap_data->destLeft); - Stream_Read_UINT16(s, bitmap_data->destTop); - Stream_Read_UINT16(s, bitmap_data->destRight); - Stream_Read_UINT16(s, bitmap_data->destBottom); - Stream_Read_UINT16(s, bitmap_data->width); - Stream_Read_UINT16(s, bitmap_data->height); - Stream_Read_UINT16(s, bitmap_data->bitsPerPixel); - Stream_Read_UINT16(s, bitmap_data->flags); - Stream_Read_UINT16(s, bitmap_data->bitmapLength); + Stream_Read_UINT16(s, bitmapData->destLeft); + Stream_Read_UINT16(s, bitmapData->destTop); + Stream_Read_UINT16(s, bitmapData->destRight); + Stream_Read_UINT16(s, bitmapData->destBottom); + Stream_Read_UINT16(s, bitmapData->width); + Stream_Read_UINT16(s, bitmapData->height); + Stream_Read_UINT16(s, bitmapData->bitsPerPixel); + Stream_Read_UINT16(s, bitmapData->flags); + Stream_Read_UINT16(s, bitmapData->bitmapLength); - if (bitmap_data->flags & BITMAP_COMPRESSION) + if (bitmapData->flags & BITMAP_COMPRESSION) { - if (!(bitmap_data->flags & NO_BITMAP_COMPRESSION_HDR)) + if (!(bitmapData->flags & NO_BITMAP_COMPRESSION_HDR)) { - Stream_Read_UINT16(s, bitmap_data->cbCompFirstRowSize); /* cbCompFirstRowSize (2 bytes) */ - Stream_Read_UINT16(s, bitmap_data->cbCompMainBodySize); /* cbCompMainBodySize (2 bytes) */ - Stream_Read_UINT16(s, bitmap_data->cbScanWidth); /* cbScanWidth (2 bytes) */ - Stream_Read_UINT16(s, bitmap_data->cbUncompressedSize); /* cbUncompressedSize (2 bytes) */ - bitmap_data->bitmapLength = bitmap_data->cbCompMainBodySize; + Stream_Read_UINT16(s, bitmapData->cbCompFirstRowSize); /* cbCompFirstRowSize (2 bytes) */ + Stream_Read_UINT16(s, bitmapData->cbCompMainBodySize); /* cbCompMainBodySize (2 bytes) */ + Stream_Read_UINT16(s, bitmapData->cbScanWidth); /* cbScanWidth (2 bytes) */ + Stream_Read_UINT16(s, bitmapData->cbUncompressedSize); /* cbUncompressedSize (2 bytes) */ + bitmapData->bitmapLength = bitmapData->cbCompMainBodySize; } - bitmap_data->compressed = TRUE; - Stream_GetPointer(s, bitmap_data->bitmapDataStream); - Stream_Seek(s, bitmap_data->bitmapLength); + bitmapData->compressed = TRUE; + Stream_GetPointer(s, bitmapData->bitmapDataStream); + Stream_Seek(s, bitmapData->bitmapLength); } else { - if (Stream_GetRemainingLength(s) < bitmap_data->bitmapLength) + if (Stream_GetRemainingLength(s) < bitmapData->bitmapLength) return FALSE; - bitmap_data->compressed = FALSE; - Stream_GetPointer(s, bitmap_data->bitmapDataStream); - Stream_Seek(s, bitmap_data->bitmapLength); + + bitmapData->compressed = FALSE; + Stream_GetPointer(s, bitmapData->bitmapDataStream); + Stream_Seek(s, bitmapData->bitmapLength); } + return TRUE; } -BOOL update_read_bitmap(rdpUpdate* update, wStream* s, BITMAP_UPDATE* bitmap_update) +BOOL update_write_bitmap_data(rdpUpdate* update, wStream* s, BITMAP_DATA* bitmapData) +{ + Stream_EnsureRemainingCapacity(s, 64 + bitmapData->bitmapLength); + + bitmapData->flags = 0; + bitmapData->cbCompFirstRowSize = 0; + + if (bitmapData->compressed) + bitmapData->flags |= BITMAP_COMPRESSION; + + if (update->context->settings->NoBitmapCompressionHeader) + { + bitmapData->flags |= NO_BITMAP_COMPRESSION_HDR; + bitmapData->cbCompMainBodySize = bitmapData->bitmapLength; + } + + Stream_Write_UINT16(s, bitmapData->destLeft); + Stream_Write_UINT16(s, bitmapData->destTop); + Stream_Write_UINT16(s, bitmapData->destRight); + Stream_Write_UINT16(s, bitmapData->destBottom); + Stream_Write_UINT16(s, bitmapData->width); + Stream_Write_UINT16(s, bitmapData->height); + Stream_Write_UINT16(s, bitmapData->bitsPerPixel); + Stream_Write_UINT16(s, bitmapData->flags); + Stream_Write_UINT16(s, bitmapData->bitmapLength); + + if (bitmapData->flags & BITMAP_COMPRESSION) + { + if (!(bitmapData->flags & NO_BITMAP_COMPRESSION_HDR)) + { + Stream_Write_UINT16(s, bitmapData->cbCompFirstRowSize); /* cbCompFirstRowSize (2 bytes) */ + Stream_Write_UINT16(s, bitmapData->cbCompMainBodySize); /* cbCompMainBodySize (2 bytes) */ + Stream_Write_UINT16(s, bitmapData->cbScanWidth); /* cbScanWidth (2 bytes) */ + Stream_Write_UINT16(s, bitmapData->cbUncompressedSize); /* cbUncompressedSize (2 bytes) */ + } + + Stream_Write(s, bitmapData->bitmapDataStream, bitmapData->bitmapLength); + } + else + { + Stream_Write(s, bitmapData->bitmapDataStream, bitmapData->bitmapLength); + } + + return TRUE; +} + +BOOL update_read_bitmap_update(rdpUpdate* update, wStream* s, BITMAP_UPDATE* bitmapUpdate) { int i; if (Stream_GetRemainingLength(s) < 2) return FALSE; - Stream_Read_UINT16(s, bitmap_update->number); /* numberRectangles (2 bytes) */ + Stream_Read_UINT16(s, bitmapUpdate->number); /* numberRectangles (2 bytes) */ - if (bitmap_update->number > bitmap_update->count) + if (bitmapUpdate->number > bitmapUpdate->count) { UINT16 count; - count = bitmap_update->number * 2; + count = bitmapUpdate->number * 2; - bitmap_update->rectangles = (BITMAP_DATA*) realloc(bitmap_update->rectangles, + bitmapUpdate->rectangles = (BITMAP_DATA*) realloc(bitmapUpdate->rectangles, sizeof(BITMAP_DATA) * count); - memset(&bitmap_update->rectangles[bitmap_update->count], 0, - sizeof(BITMAP_DATA) * (count - bitmap_update->count)); + ZeroMemory(&bitmapUpdate->rectangles[bitmapUpdate->count], + sizeof(BITMAP_DATA) * (count - bitmapUpdate->count)); - bitmap_update->count = count; + bitmapUpdate->count = count; } /* rectangles */ - for (i = 0; i < (int) bitmap_update->number; i++) + for (i = 0; i < (int) bitmapUpdate->number; i++) { - if (!update_read_bitmap_data(s, &bitmap_update->rectangles[i])) + if (!update_read_bitmap_data(update, s, &bitmapUpdate->rectangles[i])) return FALSE; } return TRUE; } +BOOL update_write_bitmap_update(rdpUpdate* update, wStream* s, BITMAP_UPDATE* bitmapUpdate) +{ + int i; + + Stream_EnsureRemainingCapacity(s, 32); + + Stream_Write_UINT16(s, UPDATE_TYPE_BITMAP); /* updateType */ + + Stream_Write_UINT16(s, bitmapUpdate->number); /* numberRectangles (2 bytes) */ + + /* rectangles */ + for (i = 0; i < (int) bitmapUpdate->number; i++) + { + if (!update_write_bitmap_data(update, s, &bitmapUpdate->rectangles[i])) + return FALSE; + } + + return TRUE; +} + BOOL update_read_palette(rdpUpdate* update, wStream* s, PALETTE_UPDATE* palette_update) { int i; @@ -353,7 +420,7 @@ BOOL update_recv(rdpUpdate* update, wStream* s) Stream_Read_UINT16(s, updateType); /* updateType (2 bytes) */ - //fprintf(stderr, "%s Update Data PDU\n", UPDATE_TYPE_STRINGS[updateType]); + //printf("%s Update Data PDU\n", UPDATE_TYPE_STRINGS[updateType]); IFCALL(update->BeginPaint, context); @@ -368,7 +435,7 @@ BOOL update_recv(rdpUpdate* update, wStream* s) break; case UPDATE_TYPE_BITMAP: - if (!update_read_bitmap(update, s, &update->bitmap_update)) + if (!update_read_bitmap_update(update, s, &update->bitmap_update)) return FALSE; IFCALL(update->BitmapUpdate, context, &update->bitmap_update); break; @@ -477,6 +544,7 @@ static void update_end_paint(rdpContext* context) if (update->numberOrders > 0) { + printf("Sending %d orders\n", update->numberOrders); fastpath_send_update_pdu(context->rdp->fastpath, FASTPATH_UPDATETYPE_ORDERS, s); } @@ -513,11 +581,16 @@ static BOOL update_check_flush(rdpContext* context, int size) { wStream* s; rdpUpdate* update = context->update; - rdpSettings* settings = context->settings; s = update->us; - if (Stream_GetPosition(s) + size + 256 >= settings->MultifragMaxRequestSize) + if (!update->us) + { + update->BeginPaint(context); + return FALSE; + } + + if (Stream_GetPosition(s) + size + 64 >= 0x3FFF) { update_flush(context); return TRUE; @@ -677,6 +750,7 @@ static void update_send_refresh_rect(rdpContext* context, BYTE count, RECTANGLE_ update_write_refresh_rect(s, count, areas); rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_REFRESH_RECT, rdp->mcs->user_id); + Stream_Release(s); } } @@ -705,6 +779,7 @@ static void update_send_suppress_output(rdpContext* context, BYTE allow, RECTANG update_write_suppress_output(s, allow, area); rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SUPPRESS_OUTPUT, rdp->mcs->user_id); + Stream_Release(s); } } @@ -717,6 +792,7 @@ static void update_send_surface_command(rdpContext* context, wStream* s) Stream_EnsureRemainingCapacity(update, Stream_GetPosition(s)); Stream_Write(update, Stream_Buffer(s), Stream_GetPosition(s)); fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, update); + Stream_Release(update); } static void update_send_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command) @@ -733,6 +809,8 @@ static void update_send_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s); update_force_flush(context); + + Stream_Release(s); } static void update_send_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker) @@ -747,6 +825,8 @@ static void update_send_surface_frame_marker(rdpContext* context, SURFACE_FRAME_ fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s); update_force_flush(context); + + Stream_Release(s); } static void update_send_frame_acknowledge(rdpContext* context, UINT32 frameId) @@ -759,6 +839,7 @@ static void update_send_frame_acknowledge(rdpContext* context, UINT32 frameId) s = rdp_data_pdu_init(rdp); Stream_Write_UINT32(s, frameId); rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FRAME_ACKNOWLEDGE, rdp->mcs->user_id); + Stream_Release(s); } } @@ -770,16 +851,35 @@ static void update_send_synchronize(rdpContext* context) s = fastpath_update_pdu_init(rdp->fastpath); Stream_Zero(s, 2); /* pad2Octets (2 bytes) */ fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SYNCHRONIZE, s); + Stream_Release(s); } static void update_send_desktop_resize(rdpContext* context) { - if (context->peer) - context->peer->activated = FALSE; - rdp_server_reactivate(context->rdp); } +static void update_send_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate) +{ + wStream* s; + rdpRdp* rdp = context->rdp; + rdpUpdate* update = context->update; + + update_force_flush(context); + + s = fastpath_update_pdu_init(rdp->fastpath); + update_write_bitmap_update(update, s, bitmapUpdate); + fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_BITMAP, s); + + update_force_flush(context); + + Stream_Release(s); +} + +/** + * Primary Drawing Orders + */ + static void update_send_dstblt(rdpContext* context, DSTBLT_ORDER* dstblt) { wStream* s; @@ -948,6 +1048,10 @@ static void update_send_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyp update->numberOrders++; } +/* + * Secondary Drawing Orders + */ + static void update_send_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* cache_bitmap) { wStream* s; @@ -978,7 +1082,7 @@ static void update_send_cache_bitmap(rdpContext* context, CACHE_BITMAP_ORDER* ca orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */ @@ -997,14 +1101,15 @@ static void update_send_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORD INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - extraFlags = 0; headerLength = 6; orderType = cache_bitmap_v2->compressed ? ORDER_TYPE_BITMAP_COMPRESSED_V2 : ORDER_TYPE_BITMAP_UNCOMPRESSED_V2; + if (context->settings->NoBitmapCompressionHeader) + cache_bitmap_v2->flags |= CBR2_NO_BITMAP_COMPRESSION_HDR; + update_check_flush(context, headerLength + update_approximate_cache_bitmap_v2_order(cache_bitmap_v2, cache_bitmap_v2->compressed, &extraFlags)); s = update->us; @@ -1019,15 +1124,13 @@ static void update_send_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORD orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3) @@ -1040,8 +1143,6 @@ static void update_send_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORD INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - extraFlags = 0; headerLength = 6; orderType = ORDER_TYPE_BITMAP_COMPRESSED_V3; @@ -1060,15 +1161,13 @@ static void update_send_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORD orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_color_table(rdpContext* context, CACHE_COLOR_TABLE_ORDER* cache_color_table) @@ -1080,8 +1179,6 @@ static void update_send_cache_color_table(rdpContext* context, CACHE_COLOR_TABLE INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - flags = 0; headerLength = 6; @@ -1099,15 +1196,13 @@ static void update_send_cache_color_table(rdpContext* context, CACHE_COLOR_TABLE orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_COLOR_TABLE); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cache_glyph) @@ -1119,8 +1214,6 @@ static void update_send_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cach INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - flags = 0; headerLength = 6; @@ -1138,15 +1231,13 @@ static void update_send_cache_glyph(rdpContext* context, CACHE_GLYPH_ORDER* cach orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_glyph_v2(rdpContext* context, CACHE_GLYPH_V2_ORDER* cache_glyph_v2) @@ -1158,8 +1249,6 @@ static void update_send_cache_glyph_v2(rdpContext* context, CACHE_GLYPH_V2_ORDER INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - flags = 0; headerLength = 6; @@ -1177,15 +1266,13 @@ static void update_send_cache_glyph_v2(rdpContext* context, CACHE_GLYPH_V2_ORDER orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cache_brush) @@ -1197,8 +1284,6 @@ static void update_send_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cach INT16 orderLength; rdpUpdate* update = context->update; - update_force_flush(context); - flags = 0; headerLength = 6; @@ -1216,17 +1301,19 @@ static void update_send_cache_brush(rdpContext* context, CACHE_BRUSH_ORDER* cach orderLength = (em - bm) - 13; Stream_SetPosition(s, bm); - Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY | ORDER_TYPE_CHANGE); /* controlFlags (1 byte) */ + Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */ Stream_Write_UINT16(s, orderLength); /* orderLength (2 bytes) */ Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */ Stream_Write_UINT8(s, ORDER_TYPE_CACHE_BRUSH); /* orderType (1 byte) */ Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } +/** + * Alternate Secondary Drawing Orders + */ + static void update_send_create_offscreen_bitmap_order(rdpContext* context, CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap) { wStream* s; @@ -1236,8 +1323,6 @@ static void update_send_create_offscreen_bitmap_order(rdpContext* context, CREAT int headerLength; rdpUpdate* update = context->update; - update_force_flush(context); - headerLength = 1; orderType = ORDER_TYPE_CREATE_OFFSCREEN_BITMAP; controlFlags = ORDER_SECONDARY | (orderType << 2); @@ -1258,8 +1343,6 @@ static void update_send_create_offscreen_bitmap_order(rdpContext* context, CREAT Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_switch_surface_order(rdpContext* context, SWITCH_SURFACE_ORDER* switch_surface) @@ -1271,8 +1354,6 @@ static void update_send_switch_surface_order(rdpContext* context, SWITCH_SURFACE int headerLength; rdpUpdate* update = context->update; - update_force_flush(context); - headerLength = 1; orderType = ORDER_TYPE_SWITCH_SURFACE; controlFlags = ORDER_SECONDARY | (orderType << 2); @@ -1293,8 +1374,6 @@ static void update_send_switch_surface_order(rdpContext* context, SWITCH_SURFACE Stream_SetPosition(s, em); update->numberOrders++; - - update_force_flush(context); } static void update_send_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer_system) @@ -1311,6 +1390,7 @@ static void update_send_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDAT updateCode = FASTPATH_UPDATETYPE_PTR_DEFAULT; fastpath_send_update_pdu(rdp->fastpath, updateCode, s); + Stream_Release(s); } static void update_write_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color) @@ -1342,6 +1422,7 @@ static void update_send_pointer_color(rdpContext* context, POINTER_COLOR_UPDATE* s = fastpath_update_pdu_init(rdp->fastpath); update_write_pointer_color(s, pointer_color); fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_COLOR, s); + Stream_Release(s); } static void update_send_pointer_new(rdpContext* context, POINTER_NEW_UPDATE* pointer_new) @@ -1353,6 +1434,7 @@ static void update_send_pointer_new(rdpContext* context, POINTER_NEW_UPDATE* poi Stream_Write_UINT16(s, pointer_new->xorBpp); /* xorBpp (2 bytes) */ update_write_pointer_color(s, &pointer_new->colorPtrAttr); fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_POINTER, s); + Stream_Release(s); } static void update_send_pointer_cached(rdpContext* context, POINTER_CACHED_UPDATE* pointer_cached) @@ -1363,6 +1445,7 @@ static void update_send_pointer_cached(rdpContext* context, POINTER_CACHED_UPDAT s = fastpath_update_pdu_init(rdp->fastpath); Stream_Write_UINT16(s, pointer_cached->cacheIndex); /* cacheIndex (2 bytes) */ fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_CACHED, s); + Stream_Release(s); } BOOL update_read_refresh_rect(rdpUpdate* update, wStream* s) @@ -1423,6 +1506,7 @@ void update_register_server_callbacks(rdpUpdate* update) update->SetBounds = update_set_bounds; update->Synchronize = update_send_synchronize; update->DesktopResize = update_send_desktop_resize; + update->BitmapUpdate = update_send_bitmap_update; update->SurfaceBits = update_send_surface_bits; update->SurfaceFrameMarker = update_send_surface_frame_marker; update->SurfaceCommand = update_send_surface_command; @@ -1499,6 +1583,8 @@ rdpUpdate* update_new(rdpRdp* rdp) update->SuppressOutput = update_send_suppress_output; update->initialState = TRUE; + + update->queue = MessageQueue_New(); } return update; @@ -1532,6 +1618,8 @@ void update_free(rdpUpdate* update) if (update->asynchronous) update_message_proxy_free(update->proxy); + MessageQueue_Free(update->queue); + free(update); } } diff --git a/libfreerdp/core/update.h b/libfreerdp/core/update.h index c3088f299..8c4dd8704 100644 --- a/libfreerdp/core/update.h +++ b/libfreerdp/core/update.h @@ -45,7 +45,7 @@ void update_free_bitmap(BITMAP_UPDATE* bitmap_update); void update_reset_state(rdpUpdate* update); void update_post_connect(rdpUpdate* update); -BOOL update_read_bitmap(rdpUpdate* update, wStream* s, BITMAP_UPDATE* bitmap_update); +BOOL update_read_bitmap_update(rdpUpdate* update, wStream* s, BITMAP_UPDATE* bitmapUpdate); BOOL update_read_palette(rdpUpdate* update, wStream* s, PALETTE_UPDATE* palette_update); BOOL update_recv_play_sound(rdpUpdate* update, wStream* s); BOOL update_recv_pointer(rdpUpdate* update, wStream* s); diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 78b9b637e..0c4bce4c9 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -100,6 +100,7 @@ BOOL tls_connect(rdpTls* tls) CryptoCert cert; long options = 0; int connection_status; + char *hostname; tls->ctx = SSL_CTX_new(TLSv1_client_method()); @@ -183,7 +184,12 @@ BOOL tls_connect(rdpTls* tls) return FALSE; } - if (!tls_verify_certificate(tls, cert, tls->settings->ServerHostname)) + if (tls->settings->GatewayEnabled) + hostname = tls->settings->GatewayHostname; + else + hostname = tls->settings->ServerHostname; + + if (!tls_verify_certificate(tls, cert, hostname)) { fprintf(stderr, "tls_connect: certificate not trusted, aborting.\n"); tls_disconnect(tls); @@ -513,6 +519,26 @@ BOOL tls_print_error(char* func, SSL* connection, int value) } } +BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname) +{ + if (strlen(hostname) == pattern_length) + { + if (memcmp((void*) hostname, (void*) pattern, pattern_length) == 0) + return TRUE; + } + + if (pattern_length > 2 && pattern[0] == '*' && pattern[1] == '.' && strlen(hostname) >= pattern_length) + { + char *check_hostname = &hostname[ strlen(hostname) - pattern_length+1 ]; + if (memcmp((void*) check_hostname, (void*) &pattern[1], pattern_length - 1) == 0 ) + { + return TRUE; + } + } + + return FALSE; +} + BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname) { int match; @@ -549,11 +575,8 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname) if (common_name != NULL) { - if (strlen(hostname) == common_name_length) - { - if (memcmp((void*) hostname, (void*) common_name, common_name_length) == 0) - hostname_match = TRUE; - } + if (tls_match_hostname(common_name, common_name_length, hostname)) + hostname_match = TRUE; } /* compare against alternative names */ @@ -562,10 +585,10 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname) { for (index = 0; index < alt_names_count; index++) { - if (strlen(hostname) == alt_names_lengths[index]) + if (tls_match_hostname(alt_names[index], alt_names_lengths[index], hostname)) { - if (memcmp((void*) hostname, (void*) alt_names[index], alt_names_lengths[index]) == 0) - hostname_match = TRUE; + hostname_match = TRUE; + break; } } } @@ -662,7 +685,8 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname) } #ifndef _WIN32 - free(common_name); + if (common_name) + free(common_name); #endif return verification_status; @@ -692,25 +716,20 @@ void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name fprintf(stderr, "@ WARNING: CERTIFICATE NAME MISMATCH! @\n"); fprintf(stderr, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); fprintf(stderr, "The hostname used for this connection (%s) \n", hostname); - - if (alt_names_count < 1) + fprintf(stderr, "does not match %s given in the certificate:\n", alt_names_count < 1 ? "the name" : "any of the names"); + fprintf(stderr, "Common Name (CN):\n"); + fprintf(stderr, "\t%s\n", common_name ? common_name : "no CN found in certificate"); + if (alt_names_count > 1) { - fprintf(stderr, "does not match the name given in the certificate:\n"); - fprintf(stderr, "%s\n", common_name); - } - else - { - fprintf(stderr, "does not match the names given in the certificate:\n"); - fprintf(stderr, "%s", common_name); - - for (index = 0; index < alt_names_count; index++) + fprintf(stderr, "Alternative names:\n"); + if (alt_names_count > 1) { - fprintf(stderr, ", %s", alt_names[index]); + for (index = 0; index < alt_names_count; index++) + { + fprintf(stderr, "\t %s\n", alt_names[index]); + } } - - fprintf(stderr, "\n"); } - fprintf(stderr, "A valid certificate for the wrong name should NOT be trusted!\n"); } diff --git a/libfreerdp/gdi/gdi.c b/libfreerdp/gdi/gdi.c index 7e64be5e2..95443ab57 100644 --- a/libfreerdp/gdi/gdi.c +++ b/libfreerdp/gdi/gdi.c @@ -739,6 +739,28 @@ void gdi_ellipse_cb(rdpContext* context, ELLIPSE_CB_ORDER* ellipse_cb) fprintf(stderr, "EllipseCB\n"); } +void gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surface_frame_marker) +{ + DEBUG_GDI("frameId %d frameAction %d", + surface_frame_marker->frameId, + surface_frame_marker->frameAction); + + /* TODO: Implement frame marker completely */ + + switch (surface_frame_marker->frameAction) + { + case SURFACECMD_FRAMEACTION_BEGIN: + break; + + case SURFACECMD_FRAMEACTION_END: + if (context->instance->settings->FrameAcknowledge > 0) + { + IFCALL(context->instance->update->SurfaceFrameAcknowledge, context, surface_frame_marker->frameId); + } + break; + } +} + int tilenum = 0; void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command) @@ -767,10 +789,10 @@ void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_co message = rfx_process_message(rfx_context, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); - DEBUG_GDI("num_rects %d num_tiles %d", message->num_rects, message->num_tiles); + DEBUG_GDI("num_rects %d num_tiles %d", message->numRects, message->numTiles); /* blit each tile */ - for (i = 0; i < message->num_tiles; i++) + for (i = 0; i < message->numTiles; i++) { tx = message->tiles[i]->x + surface_bits_command->destLeft; ty = message->tiles[i]->y + surface_bits_command->destTop; @@ -783,7 +805,7 @@ void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_co #endif - for (j = 0; j < message->num_rects; j++) + for (j = 0; j < message->numRects; j++) { gdi_SetClipRgn(gdi->primary->hdc, surface_bits_command->destLeft + message->rects[j].x, @@ -806,7 +828,7 @@ void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_co gdi->image->bitmap->bitsPerPixel = surface_bits_command->bpp; gdi->image->bitmap->bytesPerPixel = gdi->image->bitmap->bitsPerPixel / 8; gdi->image->bitmap->data = (BYTE*) realloc(gdi->image->bitmap->data, gdi->image->bitmap->width * gdi->image->bitmap->height * 4); - freerdp_image_flip(nsc_context->bmpdata, gdi->image->bitmap->data, gdi->image->bitmap->width, gdi->image->bitmap->height, 32); + freerdp_image_flip(nsc_context->BitmapData, gdi->image->bitmap->data, gdi->image->bitmap->width, gdi->image->bitmap->height, 32); gdi_BitBlt(gdi->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop, surface_bits_command->width, surface_bits_command->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); } else if (surface_bits_command->codecID == RDP_CODEC_ID_NONE) @@ -890,6 +912,7 @@ void gdi_register_update_callbacks(rdpUpdate* update) primary->EllipseCB = gdi_ellipse_cb; update->SurfaceBits = gdi_surface_bits; + update->SurfaceFrameMarker = gdi_surface_frame_marker; } void gdi_init_primary(rdpGdi* gdi) diff --git a/libfreerdp/gdi/graphics.c b/libfreerdp/gdi/graphics.c index dcc3c46e7..2be36a50a 100644 --- a/libfreerdp/gdi/graphics.c +++ b/libfreerdp/gdi/graphics.c @@ -107,7 +107,7 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, rdpGdi* gdi; BOOL status; - size = width * height * (bpp + 7) / 8; + size = width * height * ((bpp + 7) / 8); if (bitmap->data == NULL) bitmap->data = (BYTE*) malloc(size); @@ -119,7 +119,7 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, case RDP_CODEC_ID_NSCODEC: gdi = context->gdi; nsc_process_message(gdi->nsc_context, bpp, width, height, data, length); - freerdp_image_flip(((NSC_CONTEXT*)gdi->nsc_context)->bmpdata, bitmap->data, width, height, bpp); + freerdp_image_flip(((NSC_CONTEXT*)gdi->nsc_context)->BitmapData, bitmap->data, width, height, bpp); break; case RDP_CODEC_ID_REMOTEFX: gdi = context->gdi; diff --git a/libfreerdp/gdi/test/TestGdiRop3.c b/libfreerdp/gdi/test/TestGdiRop3.c index 5dec672a7..f33d68feb 100644 --- a/libfreerdp/gdi/test/TestGdiRop3.c +++ b/libfreerdp/gdi/test/TestGdiRop3.c @@ -175,7 +175,7 @@ char* gdi_convert_postfix_to_infix(char* postfix) dl = al + bl + cl + 3; - d = malloc(cl + 1); + d = malloc(dl + 1); sprintf_s(d, dl, "(%s%s%s)", b ? b : "", c, a); Stack_Push(stack, d); diff --git a/libfreerdp/locale/keyboard_layout.c b/libfreerdp/locale/keyboard_layout.c index 78e98cf5b..3869358cc 100644 --- a/libfreerdp/locale/keyboard_layout.c +++ b/libfreerdp/locale/keyboard_layout.c @@ -214,6 +214,11 @@ static const RDP_KEYBOARD_IME RDP_KEYBOARD_IME_TABLE[] = { KBD_CHINESE_TRADITIONAL_ALPHANUMERIC, "romanime.ime", "Chinese (Traditional) - Alphanumeric" } }; +void freerdp_keyboard_layouts_free(RDP_KEYBOARD_LAYOUT* layouts) +{ + free(layouts); +} + RDP_KEYBOARD_LAYOUT* freerdp_keyboard_get_layouts(DWORD types) { int num, length, i; diff --git a/libfreerdp/locale/keyboard_xkbfile.c b/libfreerdp/locale/keyboard_xkbfile.c index 2215e6fc7..8ae0948c3 100644 --- a/libfreerdp/locale/keyboard_xkbfile.c +++ b/libfreerdp/locale/keyboard_xkbfile.c @@ -154,6 +154,7 @@ XKB_KEY_NAME_SCANCODE XKB_KEY_NAME_SCANCODE_TABLE[] = { "LWIN", RDP_SCANCODE_LWIN}, { "RWIN", RDP_SCANCODE_RWIN}, { "COMP", RDP_SCANCODE_APPS}, + { "MENU", RDP_SCANCODE_APPS}, // WinMenu in xfree86 layout { "KPDV", RDP_SCANCODE_DIVIDE}, // KP! { "RCTL", RDP_SCANCODE_RCONTROL}, { "RALT", RDP_SCANCODE_RMENU}, diff --git a/libfreerdp/utils/pcap.c b/libfreerdp/utils/pcap.c index 4f7f77952..52d912bf3 100644 --- a/libfreerdp/utils/pcap.c +++ b/libfreerdp/utils/pcap.c @@ -158,7 +158,7 @@ rdpPcap* pcap_open(char* name, BOOL write) { rdpPcap* pcap; - FILE* pcap_fp = fopen(name, write ? "w+" : "r"); + FILE* pcap_fp = fopen(name, write ? "w+b" : "rb"); if (pcap_fp == NULL) { diff --git a/libfreerdp/utils/profiler.c b/libfreerdp/utils/profiler.c index f12a25cc9..3d8fae62d 100644 --- a/libfreerdp/utils/profiler.c +++ b/libfreerdp/utils/profiler.c @@ -70,7 +70,7 @@ void profiler_print(PROFILER* profiler) double elapsed_sec = stopwatch_get_elapsed_time_in_seconds(profiler->stopwatch); double avg_sec = elapsed_sec / (double) profiler->stopwatch->count; - fprintf(stderr, "| %-30.30s| %'10lu | %'9f | %'9f |\n", profiler->name, profiler->stopwatch->count, elapsed_sec, avg_sec); + fprintf(stderr, "| %-30.30s| %10lu | %9f | %9f |\n", profiler->name, profiler->stopwatch->count, elapsed_sec, avg_sec); } void profiler_print_footer() diff --git a/libfreerdp/utils/stopwatch.c b/libfreerdp/utils/stopwatch.c index a9ffd6bb6..fb1c5c161 100644 --- a/libfreerdp/utils/stopwatch.c +++ b/libfreerdp/utils/stopwatch.c @@ -26,9 +26,33 @@ #include +#ifdef _WIN32 +LARGE_INTEGER stopwatch_freq = { 0, 0 }; +#else +#include +#endif + +void stopwatch_set_time(UINT64* usecs) +{ +#ifdef _WIN32 + LARGE_INTEGER perfcount; + QueryPerformanceCounter(&perfcount); + *usecs = (perfcount.QuadPart * 1000000) / stopwatch_freq.QuadPart; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + *usecs = tv.tv_sec * 1000000 + tv.tv_usec; +#endif +} + STOPWATCH* stopwatch_create() { STOPWATCH* sw; +#ifdef _WIN32 + if (stopwatch_freq.QuadPart == 0) { + QueryPerformanceFrequency(&stopwatch_freq); + } +#endif sw = (STOPWATCH*) malloc(sizeof(STOPWATCH)); stopwatch_reset(sw); @@ -43,13 +67,13 @@ void stopwatch_free(STOPWATCH* stopwatch) void stopwatch_start(STOPWATCH* stopwatch) { - stopwatch->start = clock(); + stopwatch_set_time(&stopwatch->start); stopwatch->count++; } void stopwatch_stop(STOPWATCH* stopwatch) { - stopwatch->end = clock(); + stopwatch_set_time(&stopwatch->end); stopwatch->elapsed += (stopwatch->end - stopwatch->start); } @@ -63,22 +87,12 @@ void stopwatch_reset(STOPWATCH* stopwatch) double stopwatch_get_elapsed_time_in_seconds(STOPWATCH* stopwatch) { - return ((double) stopwatch->elapsed) / CLOCKS_PER_SEC; + return (stopwatch->elapsed/1000000.0); } void stopwatch_get_elapsed_time_in_useconds(STOPWATCH* stopwatch, UINT32* sec, UINT32* usec) { - double uelapsed; - double clocks_per_usec; - - *sec = ((UINT32) stopwatch->elapsed) / CLOCKS_PER_SEC; - uelapsed = stopwatch->elapsed - ((double)(*sec) * CLOCKS_PER_SEC); - - clocks_per_usec = (CLOCKS_PER_SEC / 1000000); - - if (clocks_per_usec > 0.0) - *usec = (UINT32)(uelapsed / clocks_per_usec); - else - *usec = 0; + *sec = stopwatch->elapsed / 1000000; + *usec = stopwatch->elapsed % 1000000; } diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 265706ba5..fed64d78c 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -19,11 +19,11 @@ add_subdirectory(common) -if(NOT WIN32) - if(WITH_SAMPLE) - add_subdirectory(Sample) - endif() +if(WITH_SAMPLE) + add_subdirectory(Sample) +endif() +if(NOT WIN32) if(WITH_X11) add_subdirectory(X11) endif() diff --git a/server/Sample/sfreerdp.c b/server/Sample/sfreerdp.c index 5dadbd013..e988a2e70 100644 --- a/server/Sample/sfreerdp.c +++ b/server/Sample/sfreerdp.c @@ -26,14 +26,13 @@ #include #include #include -#include #include -#include #include #include #include +#include #include #include "sf_audin.h" @@ -41,6 +40,10 @@ #include "sfreerdp.h" +#define SAMPLE_SERVER_USE_CLIENT_RESOLUTION 1 +#define SAMPLE_SERVER_DEFAULT_WIDTH 1024 +#define SAMPLE_SERVER_DEFAULT_HEIGHT 768 + static char* test_pcap_file = NULL; static BOOL test_dump_rfx_realtime = TRUE; @@ -48,8 +51,8 @@ void test_peer_context_new(freerdp_peer* client, testPeerContext* context) { context->rfx_context = rfx_context_new(); context->rfx_context->mode = RLGR3; - context->rfx_context->width = client->settings->DesktopWidth; - context->rfx_context->height = client->settings->DesktopHeight; + context->rfx_context->width = SAMPLE_SERVER_DEFAULT_WIDTH; + context->rfx_context->height = SAMPLE_SERVER_DEFAULT_HEIGHT; rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_R8G8B8); context->nsc_context = nsc_context_new(); @@ -473,6 +476,17 @@ BOOL tf_peer_post_connect(freerdp_peer* client) printf("Client requested desktop: %dx%dx%d\n", client->settings->DesktopWidth, client->settings->DesktopHeight, client->settings->ColorDepth); +#if (SAMPLE_SERVER_USE_CLIENT_RESOLUTION == 1) + context->rfx_context->width = client->settings->DesktopWidth; + context->rfx_context->height = client->settings->DesktopHeight; + printf("Using resolution requested by client.\n"); +#else + client->settings->DesktopWidth = context->rfx_context->width; + client->settings->DesktopHeight = context->rfx_context->height; + printf("Resizing client to %dx%d\n", client->settings->DesktopWidth, client->settings->DesktopHeight); + client->update->DesktopResize(client->update->context); +#endif + /* A real server should tag the peer as activated here and start sending updates in main loop. */ test_peer_load_icon(client); @@ -554,9 +568,11 @@ void tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) } else { - client->settings->DesktopWidth = 640; - client->settings->DesktopHeight = 480; + client->settings->DesktopWidth = SAMPLE_SERVER_DEFAULT_WIDTH; + client->settings->DesktopHeight = SAMPLE_SERVER_DEFAULT_HEIGHT; } + context->rfx_context->width = client->settings->DesktopWidth; + context->rfx_context->height = client->settings->DesktopHeight; update->DesktopResize(update->context); context->activated = FALSE; } @@ -667,6 +683,8 @@ static void* test_peer_mainloop(void* arg) client->update->RefreshRect = tf_peer_refresh_rect; client->update->SuppressOutput = tf_peer_suppress_output; + client->settings->MultifragMaxRequestSize = 0xFFFFFF; /* FIXME */ + client->Initialize(client); context = (testPeerContext*) client->context; @@ -681,7 +699,11 @@ static void* test_peer_mainloop(void* arg) printf("Failed to get FreeRDP file descriptor\n"); break; } + +#ifndef _WIN32 + /* winsock's select() only works with sockets ! */ WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount); +#endif max_fds = 0; FD_ZERO(&rfds_set); @@ -701,15 +723,27 @@ static void* test_peer_mainloop(void* arg) if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1) { +#ifdef _WIN32 + /* error codes set by windows sockets are not made available through errno ! */ + int wsa_error = WSAGetLastError(); + if (!((wsa_error == WSAEWOULDBLOCK) || + (wsa_error == WSAEINPROGRESS) || + (wsa_error == WSAEINTR))) + { + printf("select failed (WSAGetLastError: %d)\n", wsa_error); + break; + } +#else /* these are not really errors */ if (!((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINPROGRESS) || (errno == EINTR))) /* signal occurred */ { - printf("select failed\n"); + printf("select failed (errno: %d)\n", errno); break; } +#endif } if (client->CheckFileDescriptor(client) != TRUE) @@ -730,10 +764,10 @@ static void* test_peer_mainloop(void* arg) static void test_peer_accepted(freerdp_listener* instance, freerdp_peer* client) { - pthread_t th; - - pthread_create(&th, 0, test_peer_mainloop, client); - pthread_detach(th); + HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_peer_mainloop, (void*) client, 0, NULL); + if (hThread != NULL) { + CloseHandle(hThread); + } } static void test_server_mainloop(freerdp_listener* instance) @@ -800,9 +834,6 @@ int main(int argc, char* argv[]) { freerdp_listener* instance; - /* Ignore SIGPIPE, otherwise an SSL_write failure could crash your server */ - signal(SIGPIPE, SIG_IGN); - instance = freerdp_listener_new(); instance->PeerAccepted = test_peer_accepted; @@ -814,12 +845,14 @@ int main(int argc, char* argv[]) test_dump_rfx_realtime = FALSE; /* Open the server socket and start listening. */ + freerdp_wsa_startup(); if (instance->Open(instance, NULL, 3389) && instance->OpenLocal(instance, "/tmp/tfreerdp-server.0")) { /* Entering the server main loop. In a real server the listener can be run in its own thread. */ test_server_mainloop(instance); } + freerdp_wsa_cleanup(); freerdp_listener_free(instance); diff --git a/server/Windows/wf_mirage.c b/server/Windows/wf_mirage.c index 29f131e31..baafd031f 100644 --- a/server/Windows/wf_mirage.c +++ b/server/Windows/wf_mirage.c @@ -91,14 +91,24 @@ BOOL wf_mirror_driver_display_device_attach(wfInfo* wfi, DWORD mode) 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &hKey); if (status != ERROR_SUCCESS) + { + printf("Error opening RegKey: status=%0X\n", status); + if (status == ERROR_ACCESS_DENIED) + printf("access denied. Do you have admin privleges?\n"); return FALSE; + } dwSize = sizeof(DWORD); status = RegQueryValueEx(hKey, _T("Attach.ToDesktop"), NULL, &dwType, (BYTE*) &dwValue, &dwSize); if (status != ERROR_SUCCESS) + { + printf("Error querying RegKey: status=%0X\n", status); + if (status == ERROR_ACCESS_DENIED) + printf("access denied. Do you have admin privleges?\n"); return FALSE; + } if (dwValue ^ mode) //only if we want to change modes { @@ -240,6 +250,28 @@ BOOL wf_mirror_driver_map_memory(wfInfo* wfi) if (wfi->driverDC == NULL) { _tprintf(_T("Could not create device driver context!\n")); + + { + LPVOID lpMsgBuf; + DWORD dw = GetLastError(); + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, NULL ); + + // Display the error message and exit the process + + _tprintf(_T("CreateDC failed on device [%s] with error %d: %s\n"), wfi->deviceName, dw, lpMsgBuf); + + LocalFree(lpMsgBuf); + } + return FALSE; } diff --git a/server/Windows/wf_update.c b/server/Windows/wf_update.c index c8e8dc796..e6daf5c57 100644 --- a/server/Windows/wf_update.c +++ b/server/Windows/wf_update.c @@ -138,7 +138,7 @@ void wf_update_encode(wfInfo* wfi) rfx_compose_message(wfi->rfx_context, wfi->s, &rect, 1, pDataBits, width, height, stride); - wfi->frame_idx = wfi->rfx_context->frame_idx; + wfi->frame_idx = wfi->rfx_context->frameIdx; cmd->destLeft = wfi->invalid.left; cmd->destTop = wfi->invalid.top; diff --git a/server/X11/cli/xfreerdp-server b/server/X11/cli/xfreerdp-server deleted file mode 100755 index 9e837526b..000000000 Binary files a/server/X11/cli/xfreerdp-server and /dev/null differ diff --git a/server/X11/xf_cursor.c b/server/X11/xf_cursor.c index da43d8ed5..00e4abb3c 100644 --- a/server/X11/xf_cursor.c +++ b/server/X11/xf_cursor.c @@ -52,5 +52,6 @@ int xf_cursor_init(xfInfo* xfi) XFixesSelectCursorInput(xfi->display, DefaultRootWindow(xfi->display), XFixesDisplayCursorNotifyMask); #endif + return 0; } diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 226291f57..81904788c 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -63,13 +63,18 @@ endif() if(FREERDP_BUILD) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) + include_directories(${CMAKE_CURRENT_BINARY_DIR}/include PARENT_SCOPE) else() include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) + include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) endif() -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/winpr/config.h) -add_subdirectory(include) +if(NOT WITH_WAYK) + add_subdirectory(include) +endif() add_subdirectory(libwinpr) diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h index 03d06a9a8..2730ffeca 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -35,12 +35,16 @@ extern "C" { #endif typedef void* (*OBJECT_NEW_FN)(void); +typedef void (*OBJECT_INIT_FN)(void* obj); +typedef void (*OBJECT_UNINIT_FN)(void* obj); typedef void (*OBJECT_FREE_FN)(void* obj); typedef void (*OBJECT_EQUALS_FN)(void* objA, void* objB); struct _wObject { OBJECT_NEW_FN fnObjectNew; + OBJECT_INIT_FN fnObjectInit; + OBJECT_UNINIT_FN fnObjectUninit; OBJECT_FREE_FN fnObjectFree; OBJECT_EQUALS_FN fnObjectEquals; }; @@ -58,7 +62,7 @@ struct _wQueue int tail; int size; void** array; - HANDLE mutex; + CRITICAL_SECTION lock; HANDLE event; wObject object; @@ -67,8 +71,8 @@ typedef struct _wQueue wQueue; WINPR_API int Queue_Count(wQueue* queue); -WINPR_API BOOL Queue_Lock(wQueue* queue); -WINPR_API BOOL Queue_Unlock(wQueue* queue); +WINPR_API void Queue_Lock(wQueue* queue); +WINPR_API void Queue_Unlock(wQueue* queue); WINPR_API HANDLE Queue_Event(wQueue* queue); @@ -93,7 +97,7 @@ struct _wStack int size; int capacity; void** array; - HANDLE mutex; + CRITICAL_SECTION lock; BOOL synchronized; wObject object; }; @@ -125,7 +129,7 @@ struct _wArrayList int size; void** array; - HANDLE mutex; + CRITICAL_SECTION lock; wObject object; }; @@ -137,8 +141,8 @@ WINPR_API BOOL ArrayList_IsFixedSized(wArrayList* arrayList); WINPR_API BOOL ArrayList_IsReadOnly(wArrayList* arrayList); WINPR_API BOOL ArrayList_IsSynchronized(wArrayList* arrayList); -WINPR_API BOOL ArrayList_Lock(wArrayList* arrayList); -WINPR_API BOOL ArrayList_Unlock(wArrayList* arrayList); +WINPR_API void ArrayList_Lock(wArrayList* arrayList); +WINPR_API void ArrayList_Unlock(wArrayList* arrayList); WINPR_API void* ArrayList_GetItem(wArrayList* arrayList, int index); WINPR_API void ArrayList_SetItem(wArrayList* arrayList, int index, void* obj); @@ -165,19 +169,87 @@ WINPR_API void ArrayList_Free(wArrayList* arrayList); struct _wDictionary { BOOL synchronized; - HANDLE mutex; + CRITICAL_SECTION lock; }; typedef struct _wDictionary wDictionary; /* System.Collections.Specialized.ListDictionary */ +typedef struct _wListDictionaryItem wListDictionaryItem; + +struct _wListDictionaryItem +{ + void* key; + void* value; + + wListDictionaryItem* next; +}; + struct _wListDictionary { BOOL synchronized; - HANDLE mutex; + CRITICAL_SECTION lock; + + wListDictionaryItem* head; }; typedef struct _wListDictionary wListDictionary; +WINPR_API int ListDictionary_Count(wListDictionary* listDictionary); + +WINPR_API void ListDictionary_Add(wListDictionary* listDictionary, void* key, void* value); +WINPR_API void ListDictionary_Remove(wListDictionary* listDictionary, void* key); +WINPR_API void ListDictionary_Clear(wListDictionary* listDictionary); + +WINPR_API BOOL ListDictionary_Contains(wListDictionary* listDictionary, void* key); + +WINPR_API void* ListDictionary_GetItemValue(wListDictionary* listDictionary, void* key); +WINPR_API BOOL ListDictionary_SetItemValue(wListDictionary* listDictionary, void* key, void* value); + +WINPR_API wListDictionary* ListDictionary_New(BOOL synchronized); +WINPR_API void ListDictionary_Free(wListDictionary* listDictionary); + +/* System.Collections.Generic.LinkedList */ + +typedef struct _wLinkedListItem wLinkedListNode; + +struct _wLinkedListItem +{ + void* value; + wLinkedListNode* prev; + wLinkedListNode* next; +}; + +struct _wLinkedList +{ + int count; + int initial; + wLinkedListNode* head; + wLinkedListNode* tail; + wLinkedListNode* current; +}; +typedef struct _wLinkedList wLinkedList; + +WINPR_API int LinkedList_Count(wLinkedList* list); +WINPR_API void* LinkedList_First(wLinkedList* list); +WINPR_API void* LinkedList_Last(wLinkedList* list); + +WINPR_API BOOL LinkedList_Contains(wLinkedList* list, void* value); +WINPR_API void LinkedList_Clear(wLinkedList* list); + +WINPR_API void LinkedList_AddFirst(wLinkedList* list, void* value); +WINPR_API void LinkedList_AddLast(wLinkedList* list, void* value); + +WINPR_API void LinkedList_Remove(wLinkedList* list, void* value); +WINPR_API void LinkedList_RemoveFirst(wLinkedList* list); +WINPR_API void LinkedList_RemoveLast(wLinkedList* list); + +WINPR_API void LinkedList_Enumerator_Reset(wLinkedList* list); +WINPR_API void* LinkedList_Enumerator_Current(wLinkedList* list); +WINPR_API BOOL LinkedList_Enumerator_MoveNext(wLinkedList* list); + +WINPR_API wLinkedList* LinkedList_New(); +WINPR_API void LinkedList_Free(wLinkedList* list); + /* System.Collections.Generic.KeyValuePair */ struct _wKeyValuePair @@ -201,7 +273,7 @@ typedef int (*REFERENCE_FREE)(void* context, void* ptr); struct _wReferenceTable { UINT32 size; - HANDLE mutex; + CRITICAL_SECTION lock; void* context; BOOL synchronized; wReference* array; @@ -220,7 +292,7 @@ WINPR_API void ReferenceTable_Free(wReferenceTable* referenceTable); struct _wCountdownEvent { DWORD count; - HANDLE mutex; + CRITICAL_SECTION lock; HANDLE event; DWORD initialCount; }; @@ -240,18 +312,33 @@ WINPR_API void CountdownEvent_Free(wCountdownEvent* countdown); /* BufferPool */ -struct _wBufferPool +struct _wBufferPoolItem { int size; - int capacity; - void** array; - HANDLE mutex; - int fixedSize; + void* buffer; +}; +typedef struct _wBufferPoolItem wBufferPoolItem; + +struct _wBufferPool +{ + int defaultSize; DWORD alignment; BOOL synchronized; + CRITICAL_SECTION lock; + + int aSize; + int aCapacity; + wBufferPoolItem* aArray; + + int uSize; + int uCapacity; + wBufferPoolItem* uArray; }; typedef struct _wBufferPool wBufferPool; +WINPR_API int BufferPool_GetPoolSize(wBufferPool* pool); +WINPR_API int BufferPool_GetBufferSize(wBufferPool* pool, void* buffer); + WINPR_API void* BufferPool_Take(wBufferPool* pool, int bufferSize); WINPR_API void BufferPool_Return(wBufferPool* pool, void* buffer); WINPR_API void BufferPool_Clear(wBufferPool* pool); @@ -266,7 +353,7 @@ struct _wObjectPool int size; int capacity; void** array; - HANDLE mutex; + CRITICAL_SECTION lock; wObject object; BOOL synchronized; }; @@ -304,7 +391,7 @@ struct _wMessageQueue int size; int capacity; wMessage* array; - HANDLE mutex; + CRITICAL_SECTION lock; HANDLE event; }; typedef struct _wMessageQueue wMessageQueue; @@ -401,7 +488,7 @@ typedef struct _wEventType wEventType; struct _wPubSub { - HANDLE mutex; + CRITICAL_SECTION lock; BOOL synchronized; int size; @@ -410,8 +497,8 @@ struct _wPubSub }; typedef struct _wPubSub wPubSub; -WINPR_API BOOL PubSub_Lock(wPubSub* pubSub); -WINPR_API BOOL PubSub_Unlock(wPubSub* pubSub); +WINPR_API void PubSub_Lock(wPubSub* pubSub); +WINPR_API void PubSub_Unlock(wPubSub* pubSub); WINPR_API wEventType* PubSub_GetEventTypes(wPubSub* pubSub, int* count); WINPR_API void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, int count); diff --git a/winpr/include/winpr/file.h b/winpr/include/winpr/file.h index b1dfe22f5..eac472bf2 100644 --- a/winpr/include/winpr/file.h +++ b/winpr/include/winpr/file.h @@ -302,6 +302,12 @@ extern "C" { WINPR_API BOOL FilePatternMatchA(LPCSTR lpFileName, LPCSTR lpPattern); WINPR_API LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags); +WINPR_API int UnixChangeFileMode(const char* filename, int flags); + +WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName); +WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA(); +WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName); + #ifdef __cplusplus } #endif diff --git a/winpr/include/winpr/io.h b/winpr/include/winpr/io.h index 3f4365b85..c182ea4ef 100644 --- a/winpr/include/winpr/io.h +++ b/winpr/include/winpr/io.h @@ -25,6 +25,25 @@ #ifndef _WIN32 +#define GENERIC_READ 0x80000000 +#define GENERIC_WRITE 0x40000000 +#define GENERIC_EXECUTE 0x20000000 +#define GENERIC_ALL 0x10000000 + +#define DELETE 0x00010000 +#define READ_CONTROL 0x00020000 +#define WRITE_DAC 0x00040000 +#define WRITE_OWNER 0x00080000 +#define SYNCHRONIZE 0x00100000 +#define STANDARD_RIGHTS_REQUIRED 0x000F0000 +#define STANDARD_RIGHTS_READ 0x00020000 +#define STANDARD_RIGHTS_WRITE 0x00020000 +#define STANDARD_RIGHTS_EXECUTE 0x00020000 +#define STANDARD_RIGHTS_ALL 0x001F0000 +#define SPECIFIC_RIGHTS_ALL 0x0000FFFF +#define ACCESS_SYSTEM_SECURITY 0x01000000 +#define MAXIMUM_ALLOWED 0x02000000 + typedef struct _OVERLAPPED { ULONG_PTR Internal; diff --git a/winpr/include/winpr/pipe.h b/winpr/include/winpr/pipe.h index 3875c4b6c..188adf859 100644 --- a/winpr/include/winpr/pipe.h +++ b/winpr/include/winpr/pipe.h @@ -28,12 +28,92 @@ #ifndef _WIN32 +#define PIPE_UNLIMITED_INSTANCES 0xFF + +#define PIPE_ACCESS_INBOUND 0x00000001 +#define PIPE_ACCESS_OUTBOUND 0x00000002 +#define PIPE_ACCESS_DUPLEX 0x00000003 + +#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000 +#define FILE_FLAG_WRITE_THROUGH 0x80000000 +#define FILE_FLAG_OVERLAPPED 0x40000000 + +#define PIPE_CLIENT_END 0x00000000 +#define PIPE_SERVER_END 0x00000001 + +#define PIPE_TYPE_BYTE 0x00000000 +#define PIPE_TYPE_MESSAGE 0x00000004 + +#define PIPE_READMODE_BYTE 0x00000000 +#define PIPE_READMODE_MESSAGE 0x00000002 + +#define PIPE_WAIT 0x00000000 +#define PIPE_NOWAIT 0x00000001 + +#define PIPE_ACCEPT_REMOTE_CLIENTS 0x00000000 +#define PIPE_REJECT_REMOTE_CLIENTS 0x00000008 + +#define NMPWAIT_USE_DEFAULT_WAIT 0x00000000 +#define NMPWAIT_NOWAIT 0x00000001 +#define NMPWAIT_WAIT_FOREVER 0xFFFFFFFF + #ifdef __cplusplus extern "C" { #endif +/** + * Unnamed pipe + */ + WINPR_API BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize); +/** + * Named pipe + */ + +WINPR_API HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +WINPR_API HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes); + +WINPR_API BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped); + +WINPR_API BOOL DisconnectNamedPipe(HANDLE hNamedPipe); + +WINPR_API BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, + LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage); + +WINPR_API BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, + DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped); + +WINPR_API BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut); +WINPR_API BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut); + +WINPR_API BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout); + +WINPR_API BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe); + +WINPR_API BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName, ULONG ClientComputerNameLength); +WINPR_API BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName, ULONG ClientComputerNameLength); + +#ifdef UNICODE +#define CreateNamedPipe CreateNamedPipeW +#define WaitNamedPipe WaitNamedPipeW +#define GetNamedPipeClientComputerName GetNamedPipeClientComputerNameW +#else +#define CreateNamedPipe CreateNamedPipeA +#define WaitNamedPipe WaitNamedPipeA +#define GetNamedPipeClientComputerName GetNamedPipeClientComputerNameA +#endif + +/** + * Extended API + */ + +WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName); +WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA(); +WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName); + #ifdef __cplusplus } #endif diff --git a/winpr/include/winpr/platform.h b/winpr/include/winpr/platform.h index 63d1328b1..f178b0c95 100644 --- a/winpr/include/winpr/platform.h +++ b/winpr/include/winpr/platform.h @@ -128,6 +128,22 @@ /* Windows (_WIN32) */ +/* WinRT (_WINRT) */ + +#if defined(WINAPI_FAMILY) +#if (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#ifndef _WINRT +#define _WINRT 1 +#endif +#endif +#endif + +#if defined(__cplusplus_winrt) +#ifndef _WINRT +#define _WINRT 1 +#endif +#endif + /* Linux (__linux__) */ #if defined(linux) || defined(__linux) diff --git a/winpr/include/winpr/registry.h b/winpr/include/winpr/registry.h index a4021b360..53175ce28 100644 --- a/winpr/include/winpr/registry.h +++ b/winpr/include/winpr/registry.h @@ -35,22 +35,9 @@ extern "C" { #include #include +#include #include -#define DELETE 0x00010000 -#define READ_CONTROL 0x00020000 -#define WRITE_DAC 0x00040000 -#define WRITE_OWNER 0x00080000 -#define SYNCHRONIZE 0x00100000 -#define STANDARD_RIGHTS_REQUIRED 0x000f0000 - -#define STANDARD_RIGHTS_READ READ_CONTROL -#define STANDARD_RIGHTS_WRITE READ_CONTROL -#define STANDARD_RIGHTS_EXECUTE READ_CONTROL - -#define STANDARD_RIGHTS_ALL 0x001F0000 -#define SPECIFIC_RIGHTS_ALL 0x0000FFFF - #define OWNER_SECURITY_INFORMATION 0x00000001 #define GROUP_SECURITY_INFORMATION 0x00000002 #define DACL_SECURITY_INFORMATION 0x00000004 diff --git a/winpr/include/winpr/spec.h b/winpr/include/winpr/spec.h index 37b80f08f..917e8af82 100644 --- a/winpr/include/winpr/spec.h +++ b/winpr/include/winpr/spec.h @@ -53,7 +53,7 @@ #endif #ifndef DECLSPEC_NORETURN -#if (defined(__GNUC__) || defined(_MSC_VER)) +#if (defined(__GNUC__) || defined(_MSC_VER) || defined(__clang__)) #define DECLSPEC_NORETURN __declspec(noreturn) #else #define DECLSPEC_NORETURN diff --git a/winpr/include/winpr/stream.h b/winpr/include/winpr/stream.h index 0232841ad..0ad45602e 100644 --- a/winpr/include/winpr/stream.h +++ b/winpr/include/winpr/stream.h @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -57,6 +58,11 @@ WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); (((UINT16)(*(_s->pointer + 1))) << 8); \ _s->pointer += 2; } while (0) +#define Stream_Read_INT16(_s, _v) do { _v = \ + (INT16)(*_s->pointer) + \ + (((INT16)(*(_s->pointer + 1))) << 8); \ + _s->pointer += 2; } while (0) + #define Stream_Read_UINT16_BE(_s, _v) do { _v = \ (((UINT16)(*_s->pointer)) << 8) + \ (UINT16)(*(_s->pointer + 1)); \ @@ -231,7 +237,7 @@ struct _wStreamPool int uCapacity; wStream** uArray; - HANDLE mutex; + CRITICAL_SECTION lock; BOOL synchronized; size_t defaultSize; }; diff --git a/winpr/include/winpr/synch.h b/winpr/include/winpr/synch.h index c9bb0ad39..136c0877a 100644 --- a/winpr/include/winpr/synch.h +++ b/winpr/include/winpr/synch.h @@ -139,14 +139,22 @@ typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; /* Critical Section */ +#if defined(__linux__) +/** + * Linux NPTL thread synchronization primitives are implemented using + * the futex system calls ... we can't beat futex with a spin loop. + */ +#define WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT +#endif + typedef struct _RTL_CRITICAL_SECTION { - void* DebugInfo; + PVOID DebugInfo; LONG LockCount; LONG RecursionCount; - PVOID OwningThread; - PVOID LockSemaphore; - ULONG SpinCount; + HANDLE OwningThread; + HANDLE LockSemaphore; + ULONG_PTR SpinCount; } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; typedef RTL_CRITICAL_SECTION CRITICAL_SECTION; @@ -209,6 +217,8 @@ WINPR_API DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWait /* Waitable Timer */ +#define CREATE_WAITABLE_TIMER_MANUAL_RESET 0x00000001 + typedef struct _REASON_CONTEXT { ULONG Version; @@ -230,6 +240,9 @@ typedef struct _REASON_CONTEXT typedef VOID (*PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue); +WINPR_API HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName); +WINPR_API HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName); + WINPR_API HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess); WINPR_API HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess); @@ -245,9 +258,11 @@ WINPR_API HANDLE OpenWaitableTimerW(DWORD dwDesiredAccess, BOOL bInheritHandle, WINPR_API BOOL CancelWaitableTimer(HANDLE hTimer); #ifdef UNICODE +#define CreateWaitableTimer CreateWaitableTimerW #define CreateWaitableTimerEx CreateWaitableTimerExW #define OpenWaitableTimer OpenWaitableTimerW #else +#define CreateWaitableTimer CreateWaitableTimerA #define CreateWaitableTimerEx CreateWaitableTimerExA #define OpenWaitableTimer OpenWaitableTimerA #endif diff --git a/winpr/include/winpr/wtypes.h b/winpr/include/winpr/wtypes.h index a840f16ad..c05e1b86c 100644 --- a/winpr/include/winpr/wtypes.h +++ b/winpr/include/winpr/wtypes.h @@ -47,9 +47,11 @@ #if defined(__APPLE__) typedef signed char BOOL; #else +#ifndef XMD_H typedef int BOOL; #endif #endif +#endif typedef BOOL *PBOOL, *LPBOOL; @@ -86,8 +88,10 @@ typedef DWORD HCALL; typedef int INT, *LPINT; typedef signed char INT8; typedef signed short INT16; +#ifndef XMD_H typedef signed int INT32; typedef signed __int64 INT64; +#endif typedef const WCHAR* LMCSTR; typedef WCHAR* LMSTR; typedef long LONG, *PLONG, *LPLONG; @@ -97,7 +101,10 @@ typedef __int3264 LONG_PTR, *PLONG_PTR; typedef unsigned __int3264 ULONG_PTR, *PULONG_PTR; typedef signed int LONG32; + +#ifndef XMD_H typedef signed __int64 LONG64; +#endif typedef CHAR* PSTR, *LPSTR, *LPCH; typedef const CHAR *LPCSTR,*PCSTR; diff --git a/winpr/libwinpr/CMakeLists.txt b/winpr/libwinpr/CMakeLists.txt index fdb2bdac5..c5c2c6ece 100644 --- a/winpr/libwinpr/CMakeLists.txt +++ b/winpr/libwinpr/CMakeLists.txt @@ -54,7 +54,10 @@ if(MONOLITHIC_BUILD) set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib") target_link_libraries(${MODULE_NAME} ${WINPR_LIBS}) + +if(NOT WITH_WAYK) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/libwinpr") endif() diff --git a/winpr/libwinpr/crt/alignment.c b/winpr/libwinpr/crt/alignment.c index 765b3d484..bf01e6ba6 100644 --- a/winpr/libwinpr/crt/alignment.c +++ b/winpr/libwinpr/crt/alignment.c @@ -35,32 +35,20 @@ #include #endif +struct _aligned_meminfo +{ + size_t size; + void* base_addr; +}; + void* _aligned_malloc(size_t size, size_t alignment) { - void* memptr; - - /* alignment must be a power of 2 */ - - if (alignment % 2 == 1) - return NULL; - -#ifdef ANDROID - memptr = memalign(alignment, size); -#else - if (posix_memalign(&memptr, alignment, size) != 0) - return NULL; -#endif - - return memptr; + return _aligned_offset_malloc(size, alignment, 0); } void* _aligned_realloc(void* memblock, size_t size, size_t alignment) { - void* memptr = NULL; - - memptr = realloc(memblock, size); - - return memptr; + return _aligned_offset_realloc(memblock, size, alignment, 0); } void* _aligned_recalloc(void* memblock, size_t num, size_t size, size_t alignment) @@ -70,36 +58,61 @@ void* _aligned_recalloc(void* memblock, size_t num, size_t size, size_t alignmen void* _aligned_offset_malloc(size_t size, size_t alignment, size_t offset) { - void* memptr; + void* memptr, *tmpptr; + struct _aligned_meminfo *ameminfo; /* alignment must be a power of 2 */ - if (alignment % 2 == 1) return NULL; /* offset must be less than size */ - if (offset >= size) return NULL; /* minimum alignment is pointer size */ - if (alignment < sizeof(void*)) alignment = sizeof(void*); -#ifdef ANDROID - memptr = memalign(alignment, size); -#else - if (posix_memalign(&memptr, alignment, size) != 0) + /* malloc size + alignment to make sure we can align afterwards */ + tmpptr = malloc(size + alignment + sizeof(struct _aligned_meminfo)); + + if (!tmpptr) return NULL; -#endif + + memptr = (void *)((((size_t)((PBYTE)tmpptr + alignment + offset + sizeof(struct _aligned_meminfo)) & ~(alignment - 1)) - offset)); + + ameminfo = (struct _aligned_meminfo*) (((size_t)((PBYTE)memptr - sizeof(struct _aligned_meminfo)))); + ameminfo->base_addr = tmpptr; + ameminfo->size = size; return memptr; } void* _aligned_offset_realloc(void* memblock, size_t size, size_t alignment, size_t offset) { - return NULL; + void* newmem; + struct _aligned_meminfo* ameminfo; + + if (!memblock) + return _aligned_offset_malloc(size, alignment, offset); + + if (size == 0) + { + _aligned_free(memblock); + return NULL; + } + + /* The following is not very performant but a simple and working solution */ + newmem = _aligned_offset_malloc(size, alignment, offset); + + if (!newmem) + return NULL; + + ameminfo = (struct _aligned_meminfo*) (((size_t)((PBYTE)memblock - sizeof(struct _aligned_meminfo)))); + CopyMemory(newmem, memblock, ameminfo->size); + _aligned_free(memblock); + + return newmem; } void* _aligned_offset_recalloc(void* memblock, size_t num, size_t size, size_t alignment, size_t offset) @@ -114,7 +127,14 @@ size_t _aligned_msize(void* memblock, size_t alignment, size_t offset) void _aligned_free(void* memblock) { - free(memblock); + struct _aligned_meminfo* ameminfo; + + if (!memblock) + return; + + ameminfo = (struct _aligned_meminfo*) (((size_t)((PBYTE)memblock - sizeof(struct _aligned_meminfo)))); + + free(ameminfo->base_addr); } #endif diff --git a/winpr/libwinpr/file/CMakeLists.txt b/winpr/libwinpr/file/CMakeLists.txt index c690d609a..7ab377c6d 100644 --- a/winpr/libwinpr/file/CMakeLists.txt +++ b/winpr/libwinpr/file/CMakeLists.txt @@ -31,7 +31,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SO set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL MODULE winpr - MODULES winpr-crt winpr-handle) + MODULES winpr-crt winpr-handle winpr-path) if(MONOLITHIC_BUILD) diff --git a/winpr/libwinpr/file/file.c b/winpr/libwinpr/file/file.c index b43cd215c..feaf66d25 100644 --- a/winpr/libwinpr/file/file.c +++ b/winpr/libwinpr/file/file.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -125,13 +126,21 @@ #ifndef _WIN32 +#ifdef HAVE_UNISTD_H +#include +#endif + #include #include #include #include #include #include + +#include +#include #include +#include #ifdef ANDROID #include @@ -146,7 +155,59 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { - return NULL; + char* name; + int status; + HANDLE hNamedPipe; + unsigned long flags; + struct sockaddr_un s; + WINPR_NAMED_PIPE* pNamedPipe; + + if (!lpFileName) + return INVALID_HANDLE_VALUE; + + name = GetNamedPipeNameWithoutPrefixA(lpFileName); + + if (!name) + return INVALID_HANDLE_VALUE; + + free(name); + + pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE)); + hNamedPipe = (HANDLE) pNamedPipe; + + WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE); + + pNamedPipe->name = _strdup(lpFileName); + pNamedPipe->dwOpenMode = 0; + pNamedPipe->dwPipeMode = 0; + pNamedPipe->nMaxInstances = 0; + pNamedPipe->nOutBufferSize = 0; + pNamedPipe->nInBufferSize = 0; + pNamedPipe->nDefaultTimeOut = 0; + + pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpFileName); + pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpFileName); + + pNamedPipe->clientfd = socket(PF_LOCAL, SOCK_STREAM, 0); + pNamedPipe->serverfd = -1; + + if (0) + { + flags = fcntl(pNamedPipe->clientfd, F_GETFL); + flags = flags | O_NONBLOCK; + fcntl(pNamedPipe->clientfd, F_SETFL, flags); + } + + ZeroMemory(&s, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, pNamedPipe->lpFilePath); + + status = connect(pNamedPipe->clientfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)); + + if (status != 0) + return INVALID_HANDLE_VALUE; + + return hNamedPipe; } HANDLE CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, @@ -170,7 +231,6 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, { ULONG Type; PVOID Object; - WINPR_PIPE* pipe; if (!winpr_Handle_GetInfo(hFile, &Type, &Object)) return FALSE; @@ -178,6 +238,7 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, if (Type == HANDLE_TYPE_ANONYMOUS_PIPE) { int status; + WINPR_PIPE* pipe; pipe = (WINPR_PIPE*) Object; @@ -187,6 +248,30 @@ BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, return TRUE; } + else if (Type == HANDLE_TYPE_NAMED_PIPE) + { + int status; + WINPR_NAMED_PIPE* pipe; + + pipe = (WINPR_NAMED_PIPE*) Object; + + status = nNumberOfBytesToRead; + + if (pipe->clientfd != -1) + status = read(pipe->clientfd, lpBuffer, nNumberOfBytesToRead); + else + return FALSE; + + if (status < 0) + { + *lpNumberOfBytesRead = 0; + return FALSE; + } + + *lpNumberOfBytesRead = status; + + return TRUE; + } return FALSE; } @@ -208,7 +293,6 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, { ULONG Type; PVOID Object; - WINPR_PIPE* pipe; if (!winpr_Handle_GetInfo(hFile, &Type, &Object)) return FALSE; @@ -216,6 +300,7 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, if (Type == HANDLE_TYPE_ANONYMOUS_PIPE) { int status; + WINPR_PIPE* pipe; pipe = (WINPR_PIPE*) Object; @@ -225,6 +310,30 @@ BOOL WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, return TRUE; } + else if (Type == HANDLE_TYPE_NAMED_PIPE) + { + int status; + WINPR_NAMED_PIPE* pipe; + + pipe = (WINPR_NAMED_PIPE*) Object; + + status = nNumberOfBytesToWrite; + + if (pipe->clientfd != -1) + status = write(pipe->clientfd, lpBuffer, nNumberOfBytesToWrite); + else + return FALSE; + + if (status < 0) + { + *lpNumberOfBytesWritten = 0; + return FALSE; + } + + *lpNumberOfBytesWritten = status; + + return TRUE; + } return FALSE; } @@ -445,3 +554,75 @@ BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttrib #endif +/* Extended API */ + +#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\" + +char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName) +{ + char* lpFileName; + + if (!lpName) + return NULL; + + if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0) + return NULL; + + lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]); + + return lpFileName; +} + +char* GetNamedPipeUnixDomainSocketBaseFilePathA() +{ + char* lpTempPath; + char* lpPipePath; + + lpTempPath = GetKnownPath(KNOWN_PATH_TEMP); + lpPipePath = GetCombinedPath(lpTempPath, ".pipe"); + + free(lpTempPath); + + return lpPipePath; +} + +char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName) +{ + char* lpPipePath; + char* lpFileName; + char* lpFilePath; + + lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); + + lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); + lpFilePath = GetCombinedPath(lpPipePath, (char*) lpFileName); + + free(lpPipePath); + free(lpFileName); + + return lpFilePath; +} + +int UnixChangeFileMode(const char* filename, int flags) +{ +#ifndef _WIN32 + mode_t fl = 0; + + fl |= (flags & 0x4000) ? S_ISUID : 0; + fl |= (flags & 0x2000) ? S_ISGID : 0; + fl |= (flags & 0x1000) ? S_ISVTX : 0; + fl |= (flags & 0x0400) ? S_IRUSR : 0; + fl |= (flags & 0x0200) ? S_IWUSR : 0; + fl |= (flags & 0x0100) ? S_IXUSR : 0; + fl |= (flags & 0x0040) ? S_IRGRP : 0; + fl |= (flags & 0x0020) ? S_IWGRP : 0; + fl |= (flags & 0x0010) ? S_IXGRP : 0; + fl |= (flags & 0x0004) ? S_IROTH : 0; + fl |= (flags & 0x0002) ? S_IWOTH : 0; + fl |= (flags & 0x0001) ? S_IXOTH : 0; + + return chmod(filename, fl); +#else + return 0; +#endif +} diff --git a/winpr/libwinpr/handle/handle.c b/winpr/libwinpr/handle/handle.c index d198a11a2..3031b032c 100644 --- a/winpr/libwinpr/handle/handle.c +++ b/winpr/libwinpr/handle/handle.c @@ -122,6 +122,21 @@ BOOL CloseHandle(HANDLE hObject) return TRUE; } + else if (Type == HANDLE_TYPE_TIMER) + { + WINPR_TIMER* timer; + + timer = (WINPR_TIMER*) Object; + +#ifdef __linux__ + if (timer->fd != -1) + close(timer->fd); +#endif + + free(Object); + + return TRUE; + } else if (Type == HANDLE_TYPE_ANONYMOUS_PIPE) { WINPR_PIPE* pipe; @@ -137,6 +152,22 @@ BOOL CloseHandle(HANDLE hObject) return TRUE; } + else if (Type == HANDLE_TYPE_NAMED_PIPE) + { + WINPR_NAMED_PIPE* pipe; + + pipe = (WINPR_NAMED_PIPE*) Object; + + if (pipe->clientfd != -1) + close(pipe->clientfd); + + if (pipe->serverfd != -1) + close(pipe->serverfd); + + free(Object); + + return TRUE; + } return FALSE; } diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index 9e9e44a25..75faae4ea 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -47,6 +47,9 @@ static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObj { WINPR_HANDLE* wHandle; + if (handle == NULL) + return FALSE; + wHandle = (WINPR_HANDLE*) handle; *pType = wHandle->Type; diff --git a/winpr/libwinpr/interlocked/CMakeLists.txt b/winpr/libwinpr/interlocked/CMakeLists.txt index 9a5278112..b944c5d7c 100644 --- a/winpr/libwinpr/interlocked/CMakeLists.txt +++ b/winpr/libwinpr/interlocked/CMakeLists.txt @@ -34,7 +34,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SO set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL MODULE winpr - MODULES winpr-crt winpr-handle winpr-synch) + MODULES winpr-crt winpr-handle) if(MONOLITHIC_BUILD) diff --git a/winpr/libwinpr/pipe/pipe.c b/winpr/libwinpr/pipe/pipe.c index 1363763ee..241f131b9 100644 --- a/winpr/libwinpr/pipe/pipe.c +++ b/winpr/libwinpr/pipe/pipe.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -34,8 +35,17 @@ #include "../handle/handle.h" +#include +#include +#include +#include + #include "pipe.h" +/* + * Unnamed pipe + */ + BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize) { int pipe_fd[2]; @@ -69,4 +79,169 @@ BOOL CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpP return TRUE; } +/** + * Named pipe + */ + +HANDLE CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes) +{ + int status; + HANDLE hNamedPipe; + char* lpPipePath; + unsigned long flags; + struct sockaddr_un s; + WINPR_NAMED_PIPE* pNamedPipe; + + if (!lpName) + return INVALID_HANDLE_VALUE; + + pNamedPipe = (WINPR_NAMED_PIPE*) malloc(sizeof(WINPR_NAMED_PIPE)); + hNamedPipe = (HANDLE) pNamedPipe; + + WINPR_HANDLE_SET_TYPE(pNamedPipe, HANDLE_TYPE_NAMED_PIPE); + + pNamedPipe->name = _strdup(lpName); + pNamedPipe->dwOpenMode = dwOpenMode; + pNamedPipe->dwPipeMode = dwPipeMode; + pNamedPipe->nMaxInstances = nMaxInstances; + pNamedPipe->nOutBufferSize = nOutBufferSize; + pNamedPipe->nInBufferSize = nInBufferSize; + pNamedPipe->nDefaultTimeOut = nDefaultTimeOut; + + pNamedPipe->lpFileName = GetNamedPipeNameWithoutPrefixA(lpName); + pNamedPipe->lpFilePath = GetNamedPipeUnixDomainSocketFilePathA(lpName); + + lpPipePath = GetNamedPipeUnixDomainSocketBaseFilePathA(); + + if (!PathFileExistsA(lpPipePath)) + CreateDirectoryA(lpPipePath, 0); + + free(lpPipePath); + + pNamedPipe->clientfd = -1; + pNamedPipe->serverfd = socket(PF_LOCAL, SOCK_STREAM, 0); + + if (0) + { + flags = fcntl(pNamedPipe->serverfd, F_GETFL); + flags = flags | O_NONBLOCK; + fcntl(pNamedPipe->serverfd, F_SETFL, flags); + } + + ZeroMemory(&s, sizeof(struct sockaddr_un)); + s.sun_family = AF_UNIX; + strcpy(s.sun_path, pNamedPipe->lpFilePath); + unlink(s.sun_path); + + status = bind(pNamedPipe->serverfd, (struct sockaddr*) &s, sizeof(struct sockaddr_un)); + + if (status == 0) + { + status = listen(pNamedPipe->serverfd, 2); + + if (status == 0) + { + UnixChangeFileMode(pNamedPipe->lpFilePath, 0xFFFF); + } + } + + return hNamedPipe; +} + +HANDLE CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, + DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes) +{ + return NULL; +} + +BOOL ConnectNamedPipe(HANDLE hNamedPipe, LPOVERLAPPED lpOverlapped) +{ + int status; + socklen_t length; + struct sockaddr_un s; + WINPR_NAMED_PIPE* pNamedPipe; + + if (!hNamedPipe) + return FALSE; + + pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; + + length = sizeof(struct sockaddr_un); + ZeroMemory(&s, sizeof(struct sockaddr_un)); + + status = accept(pNamedPipe->serverfd, (struct sockaddr*) &s, &length); + + if (status < 0) + return FALSE; + + pNamedPipe->clientfd = status; + + return TRUE; +} + +BOOL DisconnectNamedPipe(HANDLE hNamedPipe) +{ + WINPR_NAMED_PIPE* pNamedPipe; + + pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; + + if (pNamedPipe->clientfd != -1) + { + close(pNamedPipe->clientfd); + pNamedPipe->clientfd = -1; + } + + return TRUE; +} + +BOOL PeekNamedPipe(HANDLE hNamedPipe, LPVOID lpBuffer, DWORD nBufferSize, + LPDWORD lpBytesRead, LPDWORD lpTotalBytesAvail, LPDWORD lpBytesLeftThisMessage) +{ + return TRUE; +} + +BOOL TransactNamedPipe(HANDLE hNamedPipe, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, + DWORD nOutBufferSize, LPDWORD lpBytesRead, LPOVERLAPPED lpOverlapped) +{ + return TRUE; +} + +BOOL WaitNamedPipeA(LPCSTR lpNamedPipeName, DWORD nTimeOut) +{ + return TRUE; +} + +BOOL WaitNamedPipeW(LPCWSTR lpNamedPipeName, DWORD nTimeOut) +{ + return TRUE; +} + +BOOL SetNamedPipeHandleState(HANDLE hNamedPipe, LPDWORD lpMode, LPDWORD lpMaxCollectionCount, LPDWORD lpCollectDataTimeout) +{ + WINPR_NAMED_PIPE* pNamedPipe; + + pNamedPipe = (WINPR_NAMED_PIPE*) hNamedPipe; + + if (lpMode) + pNamedPipe->dwPipeMode = *lpMode; + + return TRUE; +} + +BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe) +{ + return FALSE; +} + +BOOL GetNamedPipeClientComputerNameA(HANDLE Pipe, LPCSTR ClientComputerName, ULONG ClientComputerNameLength) +{ + return FALSE; +} + +BOOL GetNamedPipeClientComputerNameW(HANDLE Pipe, LPCWSTR ClientComputerName, ULONG ClientComputerNameLength) +{ + return FALSE; +} + #endif diff --git a/winpr/libwinpr/pipe/pipe.h b/winpr/libwinpr/pipe/pipe.h index f884fdc3f..2c326a771 100644 --- a/winpr/libwinpr/pipe/pipe.h +++ b/winpr/libwinpr/pipe/pipe.h @@ -34,6 +34,26 @@ struct winpr_pipe }; typedef struct winpr_pipe WINPR_PIPE; +struct winpr_named_pipe +{ + WINPR_HANDLE_DEF(); + + int clientfd; + int serverfd; + + const char* name; + const char* lpFileName; + const char* lpFilePath; + + DWORD dwOpenMode; + DWORD dwPipeMode; + DWORD nMaxInstances; + DWORD nOutBufferSize; + DWORD nInBufferSize; + DWORD nDefaultTimeOut; +}; +typedef struct winpr_named_pipe WINPR_NAMED_PIPE; + #endif #endif /* WINPR_PIPE_PRIVATE_H */ diff --git a/winpr/libwinpr/pipe/test/CMakeLists.txt b/winpr/libwinpr/pipe/test/CMakeLists.txt index 57abdc91e..c7b9b5a3d 100644 --- a/winpr/libwinpr/pipe/test/CMakeLists.txt +++ b/winpr/libwinpr/pipe/test/CMakeLists.txt @@ -5,7 +5,9 @@ set(MODULE_PREFIX "TEST_PIPE") set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS - TestPipeCreatePipe.c) + TestPipeCreatePipe.c + TestPipeCreateNamedPipe.c + TestPipeCreateNamedPipeOverlapped.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} @@ -16,7 +18,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} MODULE winpr - MODULES winpr-pipe) + MODULES winpr-pipe winpr-io winpr-synch winpr-thread winpr-error winpr-utils) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c new file mode 100644 index 000000000..5204217fa --- /dev/null +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipe.c @@ -0,0 +1,181 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PIPE_BUFFER_SIZE 32 + +static HANDLE ReadyEvent; + +static LPTSTR lpszPipeName = _T("\\\\.\\pipe\\winpr_test_pipe"); + +static void* named_pipe_client_thread(void* arg) +{ + HANDLE hNamedPipe; + BYTE* lpReadBuffer; + BYTE* lpWriteBuffer; + BOOL fSuccess = FALSE; + DWORD nNumberOfBytesToRead; + DWORD nNumberOfBytesToWrite; + DWORD lpNumberOfBytesRead; + DWORD lpNumberOfBytesWritten; + + WaitForSingleObject(ReadyEvent, INFINITE); + + hNamedPipe = CreateFile(lpszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (!hNamedPipe) + { + printf("Named Pipe CreateFile failure: NULL handle\n"); + return NULL; + } + + if (hNamedPipe == INVALID_HANDLE_VALUE) + { + printf("Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n"); + return NULL; + } + + lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + + lpNumberOfBytesWritten = 0; + nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + + FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x59); + + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL); + + if (!fSuccess || (lpNumberOfBytesWritten == 0)) + { + printf("Client NamedPipe WriteFile failure\n"); + return NULL; + } + + lpNumberOfBytesRead = 0; + nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL); + + if (!fSuccess || (lpNumberOfBytesRead == 0)) + { + printf("Client NamedPipe ReadFile failure\n"); + return NULL; + } + + printf("Client ReadFile (%d):\n", lpNumberOfBytesRead); + winpr_HexDump(lpReadBuffer, lpNumberOfBytesRead); + + free(lpReadBuffer); + free(lpWriteBuffer); + + CloseHandle(hNamedPipe); + + return NULL; +} + +static void* named_pipe_server_thread(void* arg) +{ + HANDLE hNamedPipe; + BYTE* lpReadBuffer; + BYTE* lpWriteBuffer; + BOOL fSuccess = FALSE; + BOOL fConnected = FALSE; + DWORD nNumberOfBytesToRead; + DWORD nNumberOfBytesToWrite; + DWORD lpNumberOfBytesRead; + DWORD lpNumberOfBytesWritten; + + hNamedPipe = CreateNamedPipe(lpszPipeName, + PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); + + if (!hNamedPipe) + { + printf("CreateNamedPipe failure: NULL handle\n"); + return NULL; + } + + if (hNamedPipe == INVALID_HANDLE_VALUE) + { + printf("CreateNamedPipe failure: INVALID_HANDLE_VALUE\n"); + return NULL; + } + + SetEvent(ReadyEvent); + + fConnected = ConnectNamedPipe(hNamedPipe, NULL); + + if (!fConnected) + fConnected = (GetLastError() == ERROR_PIPE_CONNECTED); + + if (!fConnected) + { + printf("ConnectNamedPipe failure\n"); + return NULL; + } + + lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + + lpNumberOfBytesRead = 0; + nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, &lpNumberOfBytesRead, NULL); + + if (!fSuccess || (lpNumberOfBytesRead == 0)) + { + printf("Server NamedPipe ReadFile failure\n"); + return NULL; + } + + printf("Server ReadFile (%d):\n", lpNumberOfBytesRead); + winpr_HexDump(lpReadBuffer, lpNumberOfBytesRead); + + lpNumberOfBytesWritten = 0; + nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + + FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x45); + + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, &lpNumberOfBytesWritten, NULL); + + if (!fSuccess || (lpNumberOfBytesWritten == 0)) + { + printf("Server NamedPipe WriteFile failure\n"); + return NULL; + } + + free(lpReadBuffer); + free(lpWriteBuffer); + + CloseHandle(hNamedPipe); + + return NULL; +} + +int TestPipeCreateNamedPipe(int argc, char* argv[]) +{ + HANDLE ClientThread; + HANDLE ServerThread; + + ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + ClientThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_client_thread, NULL, 0, NULL); + ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_server_thread, NULL, 0, NULL); + + WaitForSingleObject(ClientThread, INFINITE); + WaitForSingleObject(ServerThread, INFINITE); + + return 0; +} + diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c new file mode 100644 index 000000000..f5524c3f8 --- /dev/null +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c @@ -0,0 +1,240 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PIPE_BUFFER_SIZE 32 + +static HANDLE ReadyEvent; + +static LPTSTR lpszPipeName = _T("\\\\.\\pipe\\winpr_test_pipe_overlapped"); + +static void* named_pipe_client_thread(void* arg) +{ + DWORD status; + HANDLE hEvent; + HANDLE hNamedPipe; + BYTE* lpReadBuffer; + BYTE* lpWriteBuffer; + BOOL fSuccess = FALSE; + OVERLAPPED overlapped; + DWORD nNumberOfBytesToRead; + DWORD nNumberOfBytesToWrite; + DWORD NumberOfBytesTransferred; + + WaitForSingleObject(ReadyEvent, INFINITE); + + hNamedPipe = CreateFile(lpszPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + + if (!hNamedPipe) + { + printf("Named Pipe CreateFile failure: NULL handle\n"); + return NULL; + } + + if (hNamedPipe == INVALID_HANDLE_VALUE) + { + printf("Named Pipe CreateFile failure: INVALID_HANDLE_VALUE\n"); + return NULL; + } + + lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + overlapped.hEvent = hEvent; + + nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + + FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x59); + + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, NULL, &overlapped); + + if (!fSuccess) + fSuccess = (GetLastError() == ERROR_IO_PENDING); + + if (!fSuccess) + { + printf("Client NamedPipe WriteFile failure: %d\n", GetLastError()); + return NULL; + } + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Client GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, NULL, &overlapped); + + if (!fSuccess) + fSuccess = (GetLastError() == ERROR_IO_PENDING); + + if (!fSuccess) + { + printf("Client NamedPipe ReadFile failure: %d\n", GetLastError()); + return NULL; + } + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Client GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + printf("Client ReadFile (%d):\n", NumberOfBytesTransferred); + winpr_HexDump(lpReadBuffer, NumberOfBytesTransferred); + + free(lpReadBuffer); + free(lpWriteBuffer); + + CloseHandle(hNamedPipe); + CloseHandle(hEvent); + + return NULL; +} + +static void* named_pipe_server_thread(void* arg) +{ + DWORD status; + HANDLE hEvent; + HANDLE hNamedPipe; + BYTE* lpReadBuffer; + BYTE* lpWriteBuffer; + OVERLAPPED overlapped; + BOOL fSuccess = FALSE; + BOOL fConnected = FALSE; + DWORD nNumberOfBytesToRead; + DWORD nNumberOfBytesToWrite; + DWORD NumberOfBytesTransferred; + + hNamedPipe = CreateNamedPipe(lpszPipeName, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, NULL); + + if (!hNamedPipe) + { + printf("CreateNamedPipe failure: NULL handle\n"); + return NULL; + } + + if (hNamedPipe == INVALID_HANDLE_VALUE) + { + printf("CreateNamedPipe failure: INVALID_HANDLE_VALUE (%d)\n", GetLastError()); + return NULL; + } + + SetEvent(ReadyEvent); + + ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + overlapped.hEvent = hEvent; + + fConnected = ConnectNamedPipe(hNamedPipe, &overlapped); + + printf("ConnectNamedPipe status: %d\n", GetLastError()); + + if (!fConnected) + fConnected = (GetLastError() == ERROR_IO_PENDING); + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Server GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + if (!fConnected) + { + printf("ConnectNamedPipe failure: %d\n", GetLastError()); + return NULL; + } + + lpReadBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + lpWriteBuffer = (BYTE*) malloc(PIPE_BUFFER_SIZE); + + nNumberOfBytesToRead = PIPE_BUFFER_SIZE; + + ZeroMemory(lpReadBuffer, PIPE_BUFFER_SIZE); + + fSuccess = ReadFile(hNamedPipe, lpReadBuffer, nNumberOfBytesToRead, NULL, &overlapped); + + if (!fSuccess) + fSuccess = (GetLastError() == ERROR_IO_PENDING); + + if (!fSuccess) + { + printf("Server NamedPipe ReadFile failure: %d\n", GetLastError()); + return NULL; + } + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Server GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + printf("Server ReadFile (%d):\n", NumberOfBytesTransferred); + winpr_HexDump(lpReadBuffer, NumberOfBytesTransferred); + + nNumberOfBytesToWrite = PIPE_BUFFER_SIZE; + + FillMemory(lpWriteBuffer, PIPE_BUFFER_SIZE, 0x45); + + fSuccess = WriteFile(hNamedPipe, lpWriteBuffer, nNumberOfBytesToWrite, NULL, &overlapped); + + if (!fSuccess) + fSuccess = (GetLastError() == ERROR_IO_PENDING); + + if (!fSuccess) + { + printf("Server NamedPipe WriteFile failure: %d\n", GetLastError()); + return NULL; + } + + status = WaitForMultipleObjects(1, &hEvent, FALSE, INFINITE); + + NumberOfBytesTransferred = 0; + fSuccess = GetOverlappedResult(hNamedPipe, &overlapped, &NumberOfBytesTransferred, TRUE); + + printf("Server GetOverlappedResult: fSuccess: %d NumberOfBytesTransferred: %d\n", fSuccess, NumberOfBytesTransferred); + + free(lpReadBuffer); + free(lpWriteBuffer); + + CloseHandle(hNamedPipe); + CloseHandle(hEvent); + + return NULL; +} + +int TestPipeCreateNamedPipeOverlapped(int argc, char* argv[]) +{ + HANDLE ClientThread; + HANDLE ServerThread; + + ReadyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + ClientThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_client_thread, NULL, 0, NULL); + ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) named_pipe_server_thread, NULL, 0, NULL); + + WaitForSingleObject(ClientThread, INFINITE); + WaitForSingleObject(ServerThread, INFINITE); + + return 0; +} + diff --git a/winpr/libwinpr/sspi/sspi.c b/winpr/libwinpr/sspi/sspi.c index 8747e3f01..96c959995 100644 --- a/winpr/libwinpr/sspi/sspi.c +++ b/winpr/libwinpr/sspi/sspi.c @@ -248,7 +248,7 @@ void* sspi_SecureHandleGetLowerPointer(SecHandle* handle) { void* pointer; - if (!handle) + if (!handle || !SecIsValidHandle(handle)) return NULL; pointer = (void*) ~((size_t) handle->dwLower); @@ -268,7 +268,7 @@ void* sspi_SecureHandleGetUpperPointer(SecHandle* handle) { void* pointer; - if (!handle) + if (!handle || !SecIsValidHandle(handle)) return NULL; pointer = (void*) ~((size_t) handle->dwUpper); @@ -839,7 +839,7 @@ SECURITY_STATUS SEC_ENTRY CompleteAuthToken(PCtxtHandle phContext, PSecBufferDes SECURITY_STATUS SEC_ENTRY DeleteSecurityContext(PCtxtHandle phContext) { - char* Name; + char* Name = NULL; SECURITY_STATUS status; SecurityFunctionTableA* table; diff --git a/winpr/libwinpr/synch/CMakeLists.txt b/winpr/libwinpr/synch/CMakeLists.txt index 1554511a6..cd93e84f8 100644 --- a/winpr/libwinpr/synch/CMakeLists.txt +++ b/winpr/libwinpr/synch/CMakeLists.txt @@ -53,7 +53,7 @@ endif() set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL MODULE winpr - MODULES winpr-handle) + MODULES winpr-handle winpr-interlocked winpr-thread) if(MONOLITHIC_BUILD) set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE) @@ -64,3 +64,6 @@ endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") +if(BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/winpr/libwinpr/synch/critical.c b/winpr/libwinpr/synch/critical.c index 560fc512a..a547bd24e 100644 --- a/winpr/libwinpr/synch/critical.c +++ b/winpr/libwinpr/synch/critical.c @@ -3,6 +3,7 @@ * Synchronization Functions * * Copyright 2012 Marc-Andre Moreau + * Copyright 2013 Norbert Federa * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +23,9 @@ #endif #include +#include +#include +#include #include "synch.h" @@ -33,56 +37,79 @@ VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { - if (lpCriticalSection) - { - lpCriticalSection->DebugInfo = NULL; - - lpCriticalSection->LockCount = 0; - lpCriticalSection->RecursionCount = 0; - lpCriticalSection->SpinCount = 0; - - lpCriticalSection->OwningThread = NULL; - lpCriticalSection->LockSemaphore = NULL; - - lpCriticalSection->LockSemaphore = (winpr_sem_t*) malloc(sizeof(winpr_sem_t)); -#if defined __APPLE__ - semaphore_create(mach_task_self(), lpCriticalSection->LockSemaphore, SYNC_POLICY_FIFO, 1); -#else - sem_init(lpCriticalSection->LockSemaphore, 0, 1); -#endif - } + InitializeCriticalSectionEx(lpCriticalSection, 0, 0); } BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags) { + /** + * See http://msdn.microsoft.com/en-us/library/ff541979(v=vs.85).aspx + * - The LockCount field indicates the number of times that any thread has + * called the EnterCriticalSection routine for this critical section, + * minus one. This field starts at -1 for an unlocked critical section. + * Each call of EnterCriticalSection increments this value; each call of + * LeaveCriticalSection decrements it. + * - The RecursionCount field indicates the number of times that the owning + * thread has called EnterCriticalSection for this critical section. + */ + + if (Flags != 0) { + fprintf(stderr, "warning: InitializeCriticalSectionEx Flags unimplemented\n"); + } + + lpCriticalSection->DebugInfo = NULL; + lpCriticalSection->LockCount = -1; + lpCriticalSection->SpinCount = 0; + lpCriticalSection->RecursionCount = 0; + lpCriticalSection->OwningThread = NULL; + + lpCriticalSection->LockSemaphore = (winpr_sem_t*) malloc(sizeof(winpr_sem_t)); +#if defined(__APPLE__) + semaphore_create(mach_task_self(), lpCriticalSection->LockSemaphore, SYNC_POLICY_FIFO, 0); +#else + sem_init(lpCriticalSection->LockSemaphore, 0, 0); +#endif + + SetCriticalSectionSpinCount(lpCriticalSection, dwSpinCount); + return TRUE; } BOOL InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount) { - return TRUE; + return InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, 0); } DWORD SetCriticalSectionSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount) { +#if !defined(WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT) + SYSTEM_INFO sysinfo; + DWORD dwPreviousSpinCount = lpCriticalSection->SpinCount; + + if (dwSpinCount) + { + /* Don't spin on uniprocessor systems! */ + GetNativeSystemInfo(&sysinfo); + if (sysinfo.dwNumberOfProcessors < 2) + dwSpinCount = 0; + } + lpCriticalSection->SpinCount = dwSpinCount; + return dwPreviousSpinCount; +#else return 0; +#endif } -VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +VOID _WaitForCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { -#if defined __APPLE__ +#if defined(__APPLE__) semaphore_wait(*((winpr_sem_t*) lpCriticalSection->LockSemaphore)); #else sem_wait((winpr_sem_t*) lpCriticalSection->LockSemaphore); #endif } -BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) -{ - return TRUE; -} - -VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +VOID _UnWaitCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { #if defined __APPLE__ semaphore_signal(*((winpr_sem_t*) lpCriticalSection->LockSemaphore)); @@ -91,13 +118,118 @@ VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) #endif } +VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ +#if !defined(WINPR_CRITICAL_SECTION_DISABLE_SPINCOUNT) + ULONG SpinCount = lpCriticalSection->SpinCount; + + /* If we're lucky or if the current thread is already owner we can return early */ + if (SpinCount && TryEnterCriticalSection(lpCriticalSection)) + return; + + /* Spin requested times but don't compete with another waiting thread */ + while (SpinCount-- && lpCriticalSection->LockCount < 1) + { + /* Atomically try to acquire and check the if the section is free. */ + if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1) == -1) + { + lpCriticalSection->RecursionCount = 1; + lpCriticalSection->OwningThread = (HANDLE)GetCurrentThreadId(); + return; + } + /* Failed to get the lock. Let the scheduler know that we're spinning. */ + if (sched_yield()!=0) + { + /** + * On some operating systems sched_yield is a stub. + * usleep should at least trigger a context switch if any thread is waiting. + * A ThreadYield() would be nice in winpr ... + */ + usleep(1); + } + } + +#endif + + /* First try the fastest posssible path to get the lock. */ + if (InterlockedIncrement(&lpCriticalSection->LockCount)) + { + /* Section is already locked. Check if it is owned by the current thread. */ + if (lpCriticalSection->OwningThread == (HANDLE)GetCurrentThreadId()) + { + /* Recursion. No need to wait. */ + lpCriticalSection->RecursionCount++; + return; + } + + /* Section is locked by another thread. We have to wait. */ + _WaitForCriticalSection(lpCriticalSection); + } + /* We got the lock. Own it ... */ + lpCriticalSection->RecursionCount = 1; + lpCriticalSection->OwningThread = (HANDLE)GetCurrentThreadId(); +} + +BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + HANDLE current_thread = (HANDLE)GetCurrentThreadId(); + + /* Atomically acquire the the lock if the section is free. */ + if (InterlockedCompareExchange(&lpCriticalSection->LockCount, 0, -1 ) == -1) + { + lpCriticalSection->RecursionCount = 1; + lpCriticalSection->OwningThread = current_thread; + return TRUE; + } + + /* Section is already locked. Check if it is owned by the current thread. */ + if (lpCriticalSection->OwningThread == current_thread) + { + /* Recursion, return success */ + lpCriticalSection->RecursionCount++; + InterlockedIncrement(&lpCriticalSection->LockCount); + return TRUE; + } + + return FALSE; +} + +VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) +{ + /* Decrement RecursionCount and check if this is the last LeaveCriticalSection call ...*/ + if (--lpCriticalSection->RecursionCount < 1) + { + /* Last recursion, clear owner, unlock and if there are other waiting threads ... */ + lpCriticalSection->OwningThread = NULL; + if (InterlockedDecrement(&lpCriticalSection->LockCount) >= 0) + { + /* ...signal the semaphore to unblock the next waiting thread */ + _UnWaitCriticalSection(lpCriticalSection); + } + } + else + { + InterlockedDecrement(&lpCriticalSection->LockCount); + } +} + VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { + lpCriticalSection->LockCount = -1; + lpCriticalSection->SpinCount = 0; + lpCriticalSection->RecursionCount = 0; + lpCriticalSection->OwningThread = NULL; + + if (lpCriticalSection->LockSemaphore != NULL) + { #if defined __APPLE__ - semaphore_destroy(mach_task_self(), *((winpr_sem_t*) lpCriticalSection->LockSemaphore)); + semaphore_destroy(mach_task_self(), *((winpr_sem_t*) lpCriticalSection->LockSemaphore)); #else - sem_destroy((winpr_sem_t*) lpCriticalSection->LockSemaphore); + sem_destroy((winpr_sem_t*) lpCriticalSection->LockSemaphore); #endif + free(lpCriticalSection->LockSemaphore); + lpCriticalSection->LockSemaphore = NULL; + } } #endif diff --git a/winpr/libwinpr/synch/event.c b/winpr/libwinpr/synch/event.c index 173afafb7..ece585cbf 100644 --- a/winpr/libwinpr/synch/event.c +++ b/winpr/libwinpr/synch/event.c @@ -82,6 +82,9 @@ HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, WINPR_HANDLE_SET_TYPE(event, HANDLE_TYPE_EVENT); handle = (HANDLE) event; + + if (bInitialState) + SetEvent(handle); } if (!cs.LockSemaphore) diff --git a/winpr/libwinpr/synch/mutex.c b/winpr/libwinpr/synch/mutex.c index bc0e3f02b..89e6eaaf1 100644 --- a/winpr/libwinpr/synch/mutex.c +++ b/winpr/libwinpr/synch/mutex.c @@ -25,16 +25,6 @@ #include "synch.h" -/** - * CreateMutexA - * CreateMutexW - * CreateMutexExA - * CreateMutexExW - * OpenMutexA - * OpenMutexW - * ReleaseMutex - */ - #ifndef _WIN32 #include "../handle/handle.h" diff --git a/winpr/libwinpr/synch/sleep.c b/winpr/libwinpr/synch/sleep.c index 9eee1ef8d..096e24323 100644 --- a/winpr/libwinpr/synch/sleep.c +++ b/winpr/libwinpr/synch/sleep.c @@ -52,17 +52,23 @@ VOID USleep(DWORD dwMicroseconds) #ifndef _WIN32 usleep(dwMicroseconds); #else - UINT64 t1; - UINT64 t2; - UINT64 freq; + static LARGE_INTEGER freq = { 0, 0 }; + LARGE_INTEGER t1 = { 0, 0 }; + LARGE_INTEGER t2 = { 0, 0 }; - QueryPerformanceCounter((LARGE_INTEGER*) &t1); - QueryPerformanceCounter((LARGE_INTEGER*) &freq); + QueryPerformanceCounter(&t1); - do - { - QueryPerformanceCounter((LARGE_INTEGER*) &t2); + if (freq.QuadPart == 0) { + QueryPerformanceFrequency(&freq); } - while ((t2 - t1) < dwMicroseconds); + + // in order to save cpu cyles we use Sleep() for the large share ... + if (dwMicroseconds >= 1000) { + Sleep(dwMicroseconds/1000); + } + // ... and busy loop until all the requested micro seconds have passed + do { + QueryPerformanceCounter(&t2); + } while (((t2.QuadPart - t1.QuadPart)*1000000)/freq.QuadPart < dwMicroseconds); #endif } diff --git a/winpr/libwinpr/synch/synch.h b/winpr/libwinpr/synch/synch.h index 158f3bcea..f3593c536 100644 --- a/winpr/libwinpr/synch/synch.h +++ b/winpr/libwinpr/synch/synch.h @@ -20,6 +20,12 @@ #ifndef WINPR_SYNCH_PRIVATE_H #define WINPR_SYNCH_PRIVATE_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + #include #ifndef _WIN32 @@ -68,6 +74,29 @@ struct winpr_event }; typedef struct winpr_event WINPR_EVENT; +#ifdef HAVE_TIMERFD_H +#include +#include +#include +#include +#endif + +struct winpr_timer +{ + WINPR_HANDLE_DEF(); + + int fd; + LONG lPeriod; + BOOL bManualReset; + PTIMERAPCROUTINE pfnCompletionRoutine; + LPVOID lpArgToCompletionRoutine; + +#ifdef HAVE_TIMERFD_H + struct itimerspec timeout; +#endif +}; +typedef struct winpr_timer WINPR_TIMER; + #endif #endif /* WINPR_SYNCH_PRIVATE_H */ diff --git a/winpr/libwinpr/synch/test/.gitignore b/winpr/libwinpr/synch/test/.gitignore new file mode 100644 index 000000000..7107fa9df --- /dev/null +++ b/winpr/libwinpr/synch/test/.gitignore @@ -0,0 +1,3 @@ +TestSynch +TestSynch.c + diff --git a/winpr/libwinpr/synch/test/CMakeLists.txt b/winpr/libwinpr/synch/test/CMakeLists.txt new file mode 100644 index 000000000..a00169ccd --- /dev/null +++ b/winpr/libwinpr/synch/test/CMakeLists.txt @@ -0,0 +1,35 @@ + +set(MODULE_NAME "TestSynch") +set(MODULE_PREFIX "TEST_SYNCH") + +set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + +set(${MODULE_PREFIX}_TESTS + TestSynchEvent.c + TestSynchMutex.c + TestSynchCritical.c + TestSynchSemaphore.c + TestSynchWaitableTimer.c) + +create_test_sourcelist(${MODULE_PREFIX}_SRCS + ${${MODULE_PREFIX}_DRIVER} + ${${MODULE_PREFIX}_TESTS}) + +add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + +set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS + MONOLITHIC ${MONOLITHIC_BUILD} + MODULE winpr + MODULES winpr-synch winpr-sysinfo) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") + +foreach(test ${${MODULE_PREFIX}_TESTS}) + get_filename_component(TestName ${test} NAME_WE) + add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName}) +endforeach() + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test") + diff --git a/winpr/libwinpr/synch/test/TestSynchCritical.c b/winpr/libwinpr/synch/test/TestSynchCritical.c new file mode 100644 index 000000000..6ec5ca284 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchCritical.c @@ -0,0 +1,329 @@ + +#include +#include +#include +#include +#include +#include +#include + + +#define TEST_SYNC_CRITICAL_TEST1_RUNTIME_MS 500 +#define TEST_SYNC_CRITICAL_TEST1_RUNS 4 + +CRITICAL_SECTION critical; +LONG gTestValueVulnerable = 0; +LONG gTestValueSerialized = 0; + +BOOL TestSynchCritical_TriggerAndCheckRaceCondition(HANDLE OwningThread, LONG RecursionCount) +{ + /* if called unprotected this will hopefully trigger a race condition ... */ + gTestValueVulnerable++; + + if (critical.OwningThread != OwningThread) + { + printf("CriticalSection failure: OwningThread is invalid\n"); + return FALSE; + } + if (critical.RecursionCount != RecursionCount) + { + printf("CriticalSection failure: RecursionCount is invalid\n"); + return FALSE; + } + + /* ... which we try to detect using the serialized counter */ + if (gTestValueVulnerable != InterlockedIncrement(&gTestValueSerialized)) + { + printf("CriticalSection failure: Data corruption detected\n"); + return FALSE; + } + + return TRUE; +} + +/* this thread function shall increment the global dwTestValue until the PBOOL passsed in arg is FALSE */ +static PVOID TestSynchCritical_Test1(PVOID arg) +{ + int i, j, rc; + HANDLE hThread = (HANDLE)GetCurrentThreadId(); + + PBOOL pbContinueRunning = (PBOOL)arg; + + while(*pbContinueRunning) + { + EnterCriticalSection(&critical); + + rc = 1; + + if (!TestSynchCritical_TriggerAndCheckRaceCondition(hThread, rc)) + return (PVOID)1; + + /* add some random recursion level */ + j = rand()%5; + for (i=0; i 1) + dwSpinCountExpected = dwSpinCount+1; +#endif + if (dwPreviousSpinCount != dwSpinCountExpected) + { + printf("CriticalSection failure: SetCriticalSectionSpinCount returned %lu (expected: %lu)\n", dwPreviousSpinCount, dwSpinCountExpected); + goto fail; + } + + DeleteCriticalSection(&critical); + + if (dwSpinCount%2==0) + InitializeCriticalSectionAndSpinCount(&critical, dwSpinCount); + else + InitializeCriticalSectionEx(&critical, dwSpinCount, 0); + } + DeleteCriticalSection(&critical); + + + /** + * Test single-threaded recursive TryEnterCriticalSection/EnterCriticalSection/LeaveCriticalSection + * + */ + + InitializeCriticalSection(&critical); + + for (i=0; i<1000; i++) + { + if (critical.RecursionCount != i) + { + printf("CriticalSection failure: RecursionCount field is %ld instead of %d.\n", critical.RecursionCount, i); + goto fail; + } + if (i%2==0) + { + EnterCriticalSection(&critical); + } + else + { + if (TryEnterCriticalSection(&critical) == FALSE) + { + printf("CriticalSection failure: TryEnterCriticalSection failed where it should not.\n"); + goto fail; + } + } + if (critical.OwningThread != hMainThread) + { + printf("CriticalSection failure: Could not verify section ownership (loop index=%d).\n", i); + goto fail; + } + } + while (--i >= 0) + { + LeaveCriticalSection(&critical); + if (critical.RecursionCount != i) + { + printf("CriticalSection failure: RecursionCount field is %ld instead of %d.\n", critical.RecursionCount, i); + goto fail; + } + if (critical.OwningThread != (HANDLE)(i ? hMainThread : NULL)) + { + printf("CriticalSection failure: Could not verify section ownership (loop index=%d).\n", i); + goto fail; + } + } + DeleteCriticalSection(&critical); + + + /** + * Test using multiple threads modifying the same value + */ + + dwThreadCount = sysinfo.dwNumberOfProcessors > 1 ? sysinfo.dwNumberOfProcessors : 2; + + hThreads = (HANDLE*)calloc(dwThreadCount, sizeof(HANDLE)); + + for (j=0; j < TEST_SYNC_CRITICAL_TEST1_RUNS; j++) + { + dwSpinCount = j * 1000; + InitializeCriticalSectionAndSpinCount(&critical, dwSpinCount); + + gTestValueVulnerable = 0; + gTestValueSerialized = 0; + + /* the TestSynchCritical_Test1 threads shall run until bTest1Running is FALSE */ + bTest1Running = TRUE; + for (i=0; i +#include + +int TestSynchEvent(int argc, char* argv[]) +{ + HANDLE event; + + event = CreateEvent(NULL, TRUE, TRUE, NULL); + + if (!event) + { + printf("CreateEvent failure\n"); + return -1; + } + + if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForSingleObject(event, INFINITE) failure\n"); + return -1; + } + + ResetEvent(event); + + if (WaitForSingleObject(event, 0) != WAIT_TIMEOUT) + { + printf("WaitForSingleObject(event, 0) failure\n"); + return -1; + } + + SetEvent(event); + + if (WaitForSingleObject(event, 0) != WAIT_OBJECT_0) + { + printf("WaitForSingleObject(event, 0) failure\n"); + return -1; + } + + CloseHandle(event); + + return 0; +} diff --git a/winpr/libwinpr/synch/test/TestSynchMutex.c b/winpr/libwinpr/synch/test/TestSynchMutex.c new file mode 100644 index 000000000..6d2a5df43 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchMutex.c @@ -0,0 +1,21 @@ + +#include +#include + +int TestSynchMutex(int argc, char* argv[]) +{ + HANDLE mutex; + + mutex = CreateMutex(NULL, FALSE, NULL); + + if (!mutex) + { + printf("CreateMutex failure\n"); + return -1; + } + + CloseHandle(mutex); + + return 0; +} + diff --git a/winpr/libwinpr/synch/test/TestSynchSemaphore.c b/winpr/libwinpr/synch/test/TestSynchSemaphore.c new file mode 100644 index 000000000..3a9fa161c --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchSemaphore.c @@ -0,0 +1,21 @@ + +#include +#include + +int TestSynchSemaphore(int argc, char* argv[]) +{ + HANDLE semaphore; + + semaphore = CreateSemaphore(NULL, 0, 1, NULL); + + if (!semaphore) + { + printf("CreateSemaphore failure\n"); + return -1; + } + + CloseHandle(semaphore); + + return 0; +} + diff --git a/winpr/libwinpr/synch/test/TestSynchWaitableTimer.c b/winpr/libwinpr/synch/test/TestSynchWaitableTimer.c new file mode 100644 index 000000000..472a412e1 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchWaitableTimer.c @@ -0,0 +1,71 @@ + +#include +#include + +int TestSynchWaitableTimer(int argc, char* argv[]) +{ + HANDLE timer; + LONG period; + LARGE_INTEGER due; + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + + if (!timer) + { + printf("CreateWaitableTimer failure\n"); + return -1; + } + + due.QuadPart = -15000000LL; /* 1.5 seconds */ + + if (!SetWaitableTimer(timer, &due, 0, NULL, NULL, 0)) + { + printf("SetWaitableTimer failure\n"); + return -1; + } + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForSingleObject(timer, INFINITE) failure\n"); + return -1; + } + + printf("Timer Signaled\n"); + + if (WaitForSingleObject(timer, 2000) != WAIT_TIMEOUT) + { + printf("WaitForSingleObject(timer, 2000) failure\n"); + return -1; + } + + due.QuadPart = 0; + + period = 1200; /* 1.2 seconds */ + + if (!SetWaitableTimer(timer, &due, period, NULL, NULL, 0)) + { + printf("SetWaitableTimer failure\n"); + return -1; + } + + if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForSingleObject(timer, INFINITE) failure\n"); + return -1; + } + + printf("Timer Signaled\n"); + + if (WaitForMultipleObjects(1, &timer, FALSE, INFINITE) != WAIT_OBJECT_0) + { + printf("WaitForMultipleObjects(timer, INFINITE) failure\n"); + return -1; + } + + printf("Timer Signaled\n"); + + CloseHandle(timer); + + return 0; +} + diff --git a/winpr/libwinpr/synch/timer.c b/winpr/libwinpr/synch/timer.c index 2753ae563..bc32ffcdb 100644 --- a/winpr/libwinpr/synch/timer.c +++ b/winpr/libwinpr/synch/timer.c @@ -21,23 +21,66 @@ #include "config.h" #endif +#include + #include -/** - * CreateWaitableTimerExW - * OpenWaitableTimerW - * SetWaitableTimer - * SetWaitableTimerEx - * CancelWaitableTimer - */ +#include "synch.h" #ifndef _WIN32 -HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess) +#include "../handle/handle.h" + +HANDLE CreateWaitableTimerA(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCSTR lpTimerName) +{ + HANDLE handle = NULL; + WINPR_TIMER* timer; + + timer = (WINPR_TIMER*) malloc(sizeof(WINPR_TIMER)); + + if (timer) + { + int status = 0; + + WINPR_HANDLE_SET_TYPE(timer, HANDLE_TYPE_TIMER); + handle = (HANDLE) timer; + + timer->fd = -1; + timer->lPeriod = 0; + timer->bManualReset = bManualReset; + timer->pfnCompletionRoutine = NULL; + timer->lpArgToCompletionRoutine = NULL; + +#ifdef HAVE_TIMERFD_H + timer->fd = timerfd_create(CLOCK_MONOTONIC, 0); + + if (timer->fd <= 0) + return NULL; + + status = fcntl(timer->fd, F_SETFL, O_NONBLOCK); + + if (status) + return NULL; +#endif + } + + return handle; +} + +HANDLE CreateWaitableTimerW(LPSECURITY_ATTRIBUTES lpTimerAttributes, BOOL bManualReset, LPCWSTR lpTimerName) { return NULL; } +HANDLE CreateWaitableTimerExA(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess) +{ + BOOL bManualReset; + + bManualReset = (dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET) ? TRUE : FALSE; + + return CreateWaitableTimerA(lpTimerAttributes, bManualReset, lpTimerName); +} + HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess) { return NULL; @@ -46,12 +89,98 @@ HANDLE CreateWaitableTimerExW(LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR l BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, BOOL fResume) { + ULONG Type; + PVOID Object; + int status = 0; + WINPR_TIMER* timer; + LONGLONG seconds = 0; + LONGLONG nanoseconds = 0; + + if (!winpr_Handle_GetInfo(hTimer, &Type, &Object)) + return FALSE; + + if (Type != HANDLE_TYPE_TIMER) + return FALSE; + + if (!lpDueTime) + return FALSE; + + if (lPeriod < 0) + return FALSE; + + timer = (WINPR_TIMER*) Object; + + timer->lPeriod = lPeriod; /* milliseconds */ + timer->pfnCompletionRoutine = pfnCompletionRoutine; + timer->lpArgToCompletionRoutine = lpArgToCompletionRoutine; + +#ifdef HAVE_TIMERFD_H + ZeroMemory(&(timer->timeout), sizeof(struct itimerspec)); + + if (lpDueTime->QuadPart < 0) + { + LONGLONG due = lpDueTime->QuadPart * (-1); + + /* due time is in 100 nanosecond intervals */ + + seconds = (due / 10000000); + nanoseconds = ((due % 10000000) * 100); + } + else if (lpDueTime->QuadPart == 0) + { + seconds = nanoseconds = 0; + } + else + { + printf("SetWaitableTimer: implement absolute time\n"); + return FALSE; + } + + if (lPeriod > 0) + { + timer->timeout.it_interval.tv_sec = (lPeriod / 1000); /* seconds */ + timer->timeout.it_interval.tv_nsec = ((lPeriod % 1000) * 1000000); /* nanoseconds */ + } + + if (lpDueTime->QuadPart != 0) + { + timer->timeout.it_value.tv_sec = seconds; /* seconds */ + timer->timeout.it_value.tv_nsec = nanoseconds; /* nanoseconds */ + } + else + { + timer->timeout.it_value.tv_sec = timer->timeout.it_interval.tv_sec; /* seconds */ + timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec; /* nanoseconds */ + } + + status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL); + + if (status) + { + printf("SetWaitableTimer timerfd_settime failure: %d\n", status); + return FALSE; + } +#endif + return TRUE; } BOOL SetWaitableTimerEx(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay) { + ULONG Type; + PVOID Object; + WINPR_TIMER* timer; + + if (!winpr_Handle_GetInfo(hTimer, &Type, &Object)) + return FALSE; + + if (Type == HANDLE_TYPE_TIMER) + { + timer = (WINPR_TIMER*) Object; + return TRUE; + } + return TRUE; } diff --git a/winpr/libwinpr/synch/wait.c b/winpr/libwinpr/synch/wait.c index 3006fe246..dccb071ae 100644 --- a/winpr/libwinpr/synch/wait.c +++ b/winpr/libwinpr/synch/wait.c @@ -25,6 +25,8 @@ #include #endif +#include + #include #include @@ -43,6 +45,18 @@ #include "../handle/handle.h" +static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds) +{ + ts->tv_sec += dwMilliseconds / 1000L; + ts->tv_nsec += (dwMilliseconds % 1000L) * 1000000L; + + while(ts->tv_nsec >= 1000000000L) + { + ts->tv_sec ++; + ts->tv_nsec -= 1000000000L; + } +} + DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) { ULONG Type; @@ -53,22 +67,37 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) if (Type == HANDLE_TYPE_THREAD) { - int status; + int status = 0; WINPR_THREAD* thread; void* thread_status = NULL; - if (dwMilliseconds != INFINITE) - fprintf(stderr, "WaitForSingleObject: timeout not implemented for thread wait\n"); - thread = (WINPR_THREAD*) Object; - status = pthread_join(thread->thread, &thread_status); + if (thread->started) + { + if (dwMilliseconds != INFINITE) + { +#if _GNU_SOURCE + struct timespec timeout; - if (status != 0) - fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status); + clock_gettime(CLOCK_REALTIME, &timeout); + ts_add_ms(&timeout, dwMilliseconds); - if (thread_status) - thread->dwExitCode = ((DWORD) (size_t) thread_status); + status = pthread_timedjoin_np(thread->thread, &thread_status, &timeout); +#else + fprintf(stderr, "[ERROR] %s: Thread timeouts not implemented.\n", __func__); + assert(0); +#endif + } + else + status = pthread_join(thread->thread, &thread_status); + + if (status != 0) + fprintf(stderr, "WaitForSingleObject: pthread_join failure: %d\n", status); + + if (thread_status) + thread->dwExitCode = ((DWORD) (size_t) thread_status); + } } else if (Type == HANDLE_TYPE_MUTEX) { @@ -76,10 +105,21 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) mutex = (WINPR_MUTEX*) Object; +#if _GNU_SOURCE if (dwMilliseconds != INFINITE) - fprintf(stderr, "WaitForSingleObject: timeout not implemented for mutex wait\n"); + { + struct timespec timeout; - pthread_mutex_lock(&mutex->mutex); + clock_gettime(CLOCK_REALTIME, &timeout); + ts_add_ms(&timeout, dwMilliseconds); + + pthread_mutex_timedlock(&mutex->mutex, &timeout); + } + else +#endif + { + pthread_mutex_lock(&mutex->mutex); + } } else if (Type == HANDLE_TYPE_EVENT) { @@ -143,7 +183,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) length = read(semaphore->pipe_fd[0], &length, 1); if (length != 1) - return FALSE; + return WAIT_FAILED; } #else @@ -153,6 +193,51 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) sem_wait((winpr_sem_t*) semaphore->sem); #endif +#endif + } + else if (Type == HANDLE_TYPE_TIMER) + { + WINPR_TIMER* timer; + + timer = (WINPR_TIMER*) Object; + +#ifdef HAVE_EVENTFD_H + if (timer->fd != -1) + { + int status; + fd_set rfds; + UINT64 expirations; + struct timeval timeout; + + FD_ZERO(&rfds); + FD_SET(timer->fd, &rfds); + ZeroMemory(&timeout, sizeof(timeout)); + + if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0)) + { + timeout.tv_usec = dwMilliseconds * 1000; + } + + status = select(timer->fd + 1, &rfds, 0, 0, + (dwMilliseconds == INFINITE) ? NULL : &timeout); + + if (status < 0) + return WAIT_FAILED; + + if (status != 1) + return WAIT_TIMEOUT; + + status = read(timer->fd, (void*) &expirations, sizeof(UINT64)); + + if (status != 8) + return WAIT_TIMEOUT; + } + else + { + return WAIT_FAILED; + } +#else + return WAIT_FAILED; #endif } else @@ -165,6 +250,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertable) { + fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__); + assert(0); return WAIT_OBJECT_0; } @@ -181,12 +268,16 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl if (!nCount) return WAIT_FAILED; + maxfd = 0; FD_ZERO(&fds); ZeroMemory(&timeout, sizeof(timeout)); if (bWaitAll) + { fprintf(stderr, "WaitForMultipleObjects: bWaitAll not yet implemented\n"); + assert(0); + } for (index = 0; index < nCount; index++) { @@ -205,11 +296,19 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl return WAIT_FAILED; #endif } + else if (Type == HANDLE_TYPE_TIMER) + { + WINPR_TIMER* timer = (WINPR_TIMER*) Object; + fd = timer->fd; + } else { return WAIT_FAILED; } + if (fd == -1) + return WAIT_FAILED; + FD_SET(fd, &fds); if (fd > maxfd) @@ -235,19 +334,40 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl winpr_Handle_GetInfo(lpHandles[index], &Type, &Object); if (Type == HANDLE_TYPE_EVENT) + { fd = ((WINPR_EVENT*) Object)->pipe_fd[0]; + } else if (Type == HANDLE_TYPE_SEMAPHORE) + { fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0]; + } + else if (Type == HANDLE_TYPE_TIMER) + { + WINPR_TIMER* timer = (WINPR_TIMER*) Object; + fd = timer->fd; + } if (FD_ISSET(fd, &fds)) { if (Type == HANDLE_TYPE_SEMAPHORE) { - int length = read(fd, &length, 1); + int length; + + length = read(fd, &length, 1); if (length != 1) return WAIT_FAILED; } + else if (Type == HANDLE_TYPE_TIMER) + { + int length; + UINT64 expirations; + + length = read(fd, (void*) &expirations, sizeof(UINT64)); + + if (length != 8) + return WAIT_FAILED; + } return (WAIT_OBJECT_0 + index); } @@ -258,11 +378,15 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl DWORD WaitForMultipleObjectsEx(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds, BOOL bAlertable) { + fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__); + assert(0); return 0; } DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable) { + fprintf(stderr, "[ERROR] %s: Function not implemented.\n", __func__); + assert(0); return 0; } diff --git a/winpr/libwinpr/thread/process.c b/winpr/libwinpr/thread/process.c index b5cc87858..76c4f127e 100644 --- a/winpr/libwinpr/thread/process.c +++ b/winpr/libwinpr/thread/process.c @@ -87,7 +87,7 @@ BOOL CreateProcessAsUserW(HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCom return TRUE; } -VOID ExitProcess(UINT uExitCode) +DECLSPEC_NORETURN VOID ExitProcess(UINT uExitCode) { } diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 2a8c53afe..d7db7b6d6 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -25,6 +25,7 @@ set(${MODULE_PREFIX}_COLLECTIONS_SRCS collections/Reference.c collections/ArrayList.c collections/Dictionary.c + collections/LinkedList.c collections/ListDictionary.c collections/KeyValuePair.c collections/CountdownEvent.c diff --git a/winpr/libwinpr/utils/collections/ArrayList.c b/winpr/libwinpr/utils/collections/ArrayList.c index 157b365b6..a337e2169 100644 --- a/winpr/libwinpr/utils/collections/ArrayList.c +++ b/winpr/libwinpr/utils/collections/ArrayList.c @@ -83,18 +83,18 @@ BOOL ArrayList_IsSynchronized(wArrayList* arrayList) * Lock access to the ArrayList */ -BOOL ArrayList_Lock(wArrayList* arrayList) +void ArrayList_Lock(wArrayList* arrayList) { - return (WaitForSingleObject(arrayList->mutex, INFINITE) == WAIT_OBJECT_0) ? TRUE : FALSE; + EnterCriticalSection(&arrayList->lock); } /** * Unlock access to the ArrayList */ -BOOL ArrayList_Unlock(wArrayList* arrayList) +void ArrayList_Unlock(wArrayList* arrayList) { - return ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -164,7 +164,7 @@ void ArrayList_Clear(wArrayList* arrayList) int index; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); for (index = 0; index < arrayList->size; index++) { @@ -177,7 +177,7 @@ void ArrayList_Clear(wArrayList* arrayList) arrayList->size = 0; if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -187,10 +187,10 @@ void ArrayList_Clear(wArrayList* arrayList) BOOL ArrayList_Contains(wArrayList* arrayList, void* obj) { if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); return FALSE; } @@ -204,7 +204,7 @@ int ArrayList_Add(wArrayList* arrayList, void* obj) int index; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if (arrayList->size + 1 > arrayList->capacity) { @@ -216,7 +216,7 @@ int ArrayList_Add(wArrayList* arrayList, void* obj) index = arrayList->size; if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); return index; } @@ -228,7 +228,7 @@ int ArrayList_Add(wArrayList* arrayList, void* obj) void ArrayList_Insert(wArrayList* arrayList, int index, void* obj) { if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if ((index >= 0) && (index < arrayList->size)) { @@ -237,7 +237,7 @@ void ArrayList_Insert(wArrayList* arrayList, int index, void* obj) } if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -250,7 +250,7 @@ void ArrayList_Remove(wArrayList* arrayList, void* obj) BOOL found = FALSE; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); for (index = 0; index < arrayList->size; index++) { @@ -265,7 +265,7 @@ void ArrayList_Remove(wArrayList* arrayList, void* obj) ArrayList_Shift(arrayList, index, -1); if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -275,7 +275,7 @@ void ArrayList_Remove(wArrayList* arrayList, void* obj) void ArrayList_RemoveAt(wArrayList* arrayList, int index) { if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if ((index >= 0) && (index < arrayList->size)) { @@ -283,7 +283,7 @@ void ArrayList_RemoveAt(wArrayList* arrayList, int index) } if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); } /** @@ -302,7 +302,7 @@ int ArrayList_IndexOf(wArrayList* arrayList, void* obj, int startIndex, int coun BOOL found = FALSE; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if (startIndex < 0) startIndex = 0; @@ -323,7 +323,7 @@ int ArrayList_IndexOf(wArrayList* arrayList, void* obj, int startIndex, int coun index = -1; if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); return index; } @@ -344,7 +344,7 @@ int ArrayList_LastIndexOf(wArrayList* arrayList, void* obj, int startIndex, int BOOL found = FALSE; if (arrayList->synchronized) - WaitForSingleObject(arrayList->mutex, INFINITE); + EnterCriticalSection(&arrayList->lock); if (startIndex < 0) startIndex = 0; @@ -365,7 +365,7 @@ int ArrayList_LastIndexOf(wArrayList* arrayList, void* obj, int startIndex, int index = -1; if (arrayList->synchronized) - ReleaseMutex(arrayList->mutex); + LeaveCriticalSection(&arrayList->lock); return index; } @@ -390,7 +390,7 @@ wArrayList* ArrayList_New(BOOL synchronized) arrayList->array = (void**) malloc(sizeof(void*) * arrayList->capacity); - arrayList->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&arrayList->lock, 4000); ZeroMemory(&arrayList->object, sizeof(wObject)); } @@ -402,7 +402,7 @@ void ArrayList_Free(wArrayList* arrayList) { ArrayList_Clear(arrayList); - CloseHandle(arrayList->mutex); + DeleteCriticalSection(&arrayList->lock); free(arrayList->array); free(arrayList); } diff --git a/winpr/libwinpr/utils/collections/BufferPool.c b/winpr/libwinpr/utils/collections/BufferPool.c index d10ba1360..e5b39114f 100644 --- a/winpr/libwinpr/utils/collections/BufferPool.c +++ b/winpr/libwinpr/utils/collections/BufferPool.c @@ -34,37 +34,172 @@ * Methods */ +void BufferPool_ShiftAvailable(wBufferPool* pool, int index, int count) +{ + if (count > 0) + { + if (pool->aSize + count > pool->aCapacity) + { + pool->aCapacity *= 2; + pool->aArray = (wBufferPoolItem*) realloc(pool->aArray, sizeof(wBufferPoolItem) * pool->aCapacity); + } + + MoveMemory(&pool->aArray[index + count], &pool->aArray[index], (pool->aSize - index) * sizeof(wBufferPoolItem)); + pool->aSize += count; + } + else if (count < 0) + { + MoveMemory(&pool->aArray[index], &pool->aArray[index - count], (pool->aSize - index) * sizeof(wBufferPoolItem)); + pool->aSize += count; + } +} + +void BufferPool_ShiftUsed(wBufferPool* pool, int index, int count) +{ + if (count > 0) + { + if (pool->uSize + count > pool->uCapacity) + { + pool->uCapacity *= 2; + pool->uArray = (wBufferPoolItem*) realloc(pool->uArray, sizeof(wBufferPoolItem) * pool->uCapacity); + } + + MoveMemory(&pool->uArray[index + count], &pool->uArray[index], (pool->uSize - index) * sizeof(wBufferPoolItem)); + pool->uSize += count; + } + else if (count < 0) + { + MoveMemory(&pool->uArray[index], &pool->uArray[index - count], (pool->uSize - index) * sizeof(wBufferPoolItem)); + pool->uSize += count; + } +} + +/** + * Get the buffer pool size + */ + +int BufferPool_GetPoolSize(wBufferPool* pool) +{ + int size; + + if (pool->synchronized) + EnterCriticalSection(&pool->lock); + + size = pool->uSize; + + if (pool->synchronized) + LeaveCriticalSection(&pool->lock); + + return size; +} + +/** + * Get the size of a pooled buffer + */ + +int BufferPool_GetBufferSize(wBufferPool* pool, void* buffer) +{ + int size = 0; + int index = 0; + BOOL found = FALSE; + + if (pool->synchronized) + EnterCriticalSection(&pool->lock); + + for (index = 0; index < pool->uSize; index++) + { + if (pool->uArray[index].buffer == buffer) + { + size = pool->uArray[index].size; + found = TRUE; + break; + } + } + + if (pool->synchronized) + LeaveCriticalSection(&pool->lock); + + return (found) ? size : -1; +} + /** * Gets a buffer of at least the specified size from the pool. */ -void* BufferPool_Take(wBufferPool* pool, int bufferSize) +void* BufferPool_Take(wBufferPool* pool, int size) { + int index; + int maxSize; + int maxIndex; + int foundIndex; + BOOL found = FALSE; void* buffer = NULL; if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); - if (pool->fixedSize) + maxSize = 0; + maxIndex = 0; + + if (size < 1) + size = pool->defaultSize; + + for (index = 0; index < pool->aSize; index++) { - if (pool->size > 0) - buffer = pool->array[--(pool->size)]; - - if (!buffer) + if (pool->aArray[index].size > maxSize) { - if (pool->alignment) - buffer = _aligned_malloc(pool->fixedSize, pool->alignment); - else - buffer = malloc(pool->fixedSize); + maxIndex = index; + maxSize = pool->aArray[index].size; } + + if (pool->aArray[index].size >= size) + { + foundIndex = index; + found = TRUE; + break; + } + } + + if (!found && maxSize) + { + foundIndex = maxIndex; + found = TRUE; + } + + if (!found) + { + if (pool->alignment) + buffer = _aligned_malloc(size, pool->alignment); + else + buffer = malloc(size); } else { - fprintf(stderr, "Variable-size BufferPool not yet implemented\n"); + buffer = pool->aArray[index].buffer; + + if (maxSize < size) + { + if (pool->alignment) + buffer = _aligned_realloc(buffer, size, pool->alignment); + else + buffer = realloc(buffer, size); + } + + BufferPool_ShiftAvailable(pool, foundIndex, -1); } + if (pool->uSize + 1 > pool->uCapacity) + { + pool->uCapacity *= 2; + pool->uArray = (wBufferPoolItem*) realloc(pool->uArray, sizeof(wBufferPoolItem) * pool->uCapacity); + } + + pool->uArray[pool->uSize].buffer = buffer; + pool->uArray[pool->uSize].size = size; + (pool->uSize)++; + if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); return buffer; } @@ -75,19 +210,43 @@ void* BufferPool_Take(wBufferPool* pool, int bufferSize) void BufferPool_Return(wBufferPool* pool, void* buffer) { - if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + int size = 0; + int index = 0; + BOOL found = FALSE; - if ((pool->size + 1) >= pool->capacity) + if (pool->synchronized) + EnterCriticalSection(&pool->lock); + + for (index = 0; index < pool->uSize; index++) { - pool->capacity *= 2; - pool->array = (void**) realloc(pool->array, sizeof(void*) * pool->capacity); + if (pool->uArray[index].buffer == buffer) + { + found = TRUE; + break; + } } - pool->array[(pool->size)++] = buffer; + if (found) + { + size = pool->uArray[index].size; + BufferPool_ShiftUsed(pool, index, -1); + } + + if (size) + { + if ((pool->aSize + 1) >= pool->aCapacity) + { + pool->aCapacity *= 2; + pool->aArray = (wBufferPoolItem*) realloc(pool->aArray, sizeof(wBufferPoolItem) * pool->aCapacity); + } + + pool->aArray[pool->aSize].buffer = buffer; + pool->aArray[pool->aSize].size = size; + (pool->aSize)++; + } if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -97,27 +256,37 @@ void BufferPool_Return(wBufferPool* pool, void* buffer) void BufferPool_Clear(wBufferPool* pool) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); - while (pool->size > 0) + while (pool->aSize > 0) { - (pool->size)--; + (pool->aSize)--; if (pool->alignment) - _aligned_free(pool->array[pool->size]); + _aligned_free(pool->aArray[pool->aSize].buffer); else - free(pool->array[pool->size]); + free(pool->aArray[pool->aSize].buffer); + } + + while (pool->uSize > 0) + { + (pool->uSize)--; + + if (pool->alignment) + _aligned_free(pool->uArray[pool->uSize].buffer); + else + free(pool->uArray[pool->uSize].buffer); } if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** * Construction, Destruction */ -wBufferPool* BufferPool_New(BOOL synchronized, int fixedSize, DWORD alignment) +wBufferPool* BufferPool_New(BOOL synchronized, int defaultSize, DWORD alignment) { wBufferPool* pool = NULL; @@ -125,25 +294,24 @@ wBufferPool* BufferPool_New(BOOL synchronized, int fixedSize, DWORD alignment) if (pool) { - pool->fixedSize = fixedSize; + pool->defaultSize = defaultSize; - if (pool->fixedSize < 0) - pool->fixedSize = 0; + if (pool->defaultSize < 0) + pool->defaultSize = 0; pool->alignment = alignment; pool->synchronized = synchronized; if (pool->synchronized) - pool->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&pool->lock, 4000); - if (!pool->fixedSize) - { - fprintf(stderr, "Variable-size BufferPool not yet implemented\n"); - } + pool->aSize = 0; + pool->aCapacity = 32; + pool->aArray = (wBufferPoolItem*) malloc(sizeof(wBufferPoolItem) * pool->aCapacity); - pool->size = 0; - pool->capacity = 32; - pool->array = (void**) malloc(sizeof(void*) * pool->capacity); + pool->uSize = 0; + pool->uCapacity = 32; + pool->uArray = (wBufferPoolItem*) malloc(sizeof(wBufferPoolItem) * pool->uCapacity); } return pool; @@ -156,9 +324,10 @@ void BufferPool_Free(wBufferPool* pool) BufferPool_Clear(pool); if (pool->synchronized) - CloseHandle(pool->mutex); + DeleteCriticalSection(&pool->lock); - free(pool->array); + free(pool->aArray); + free(pool->uArray); free(pool); } diff --git a/winpr/libwinpr/utils/collections/CountdownEvent.c b/winpr/libwinpr/utils/collections/CountdownEvent.c index 787c7e31b..ea50f4219 100644 --- a/winpr/libwinpr/utils/collections/CountdownEvent.c +++ b/winpr/libwinpr/utils/collections/CountdownEvent.c @@ -89,14 +89,14 @@ HANDLE CountdownEvent_WaitHandle(wCountdownEvent* countdown) void CountdownEvent_AddCount(wCountdownEvent* countdown, DWORD signalCount) { - WaitForSingleObject(countdown->mutex, INFINITE); + EnterCriticalSection(&countdown->lock); countdown->count += signalCount; if (countdown->count > 0) ResetEvent(countdown->event); - ReleaseMutex(countdown->mutex); + LeaveCriticalSection(&countdown->lock); } /** @@ -111,7 +111,7 @@ BOOL CountdownEvent_Signal(wCountdownEvent* countdown, DWORD signalCount) status = newStatus = oldStatus = FALSE; - WaitForSingleObject(countdown->mutex, INFINITE); + EnterCriticalSection(&countdown->lock); if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0) oldStatus = TRUE; @@ -130,7 +130,7 @@ BOOL CountdownEvent_Signal(wCountdownEvent* countdown, DWORD signalCount) status = TRUE; } - ReleaseMutex(countdown->mutex); + LeaveCriticalSection(&countdown->lock); return status; } @@ -158,7 +158,7 @@ wCountdownEvent* CountdownEvent_New(DWORD initialCount) { countdown->count = initialCount; countdown->initialCount = initialCount; - countdown->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&countdown->lock, 4000); countdown->event = CreateEvent(NULL, TRUE, FALSE, NULL); if (countdown->count == 0) @@ -170,7 +170,7 @@ wCountdownEvent* CountdownEvent_New(DWORD initialCount) void CountdownEvent_Free(wCountdownEvent* countdown) { - CloseHandle(countdown->mutex); + DeleteCriticalSection(&countdown->lock); CloseHandle(countdown->event); free(countdown); diff --git a/winpr/libwinpr/utils/collections/LinkedList.c b/winpr/libwinpr/utils/collections/LinkedList.c new file mode 100644 index 000000000..f96f9d7c0 --- /dev/null +++ b/winpr/libwinpr/utils/collections/LinkedList.c @@ -0,0 +1,339 @@ +/** + * WinPR: Windows Portable Runtime + * System.Collections.Generic.LinkedList + * + * Copyright 2013 Marc-Andre Moreau + * + * 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 + +/** + * C equivalent of the C# LinkedList Class: + * http://msdn.microsoft.com/en-us/library/he2s3bh7.aspx + * + * Internal implementation uses a doubly-linked list + */ + +/** + * Properties + */ + +/** + * Gets the number of nodes actually contained in the LinkedList. + */ + +int LinkedList_Count(wLinkedList* list) +{ + return list->count; +} + +/** + * Gets the first node of the LinkedList. + */ + +void* LinkedList_First(wLinkedList* list) +{ + if (list->head) + return list->head->value; + else + return NULL; +} + +/** + * Gets the last node of the LinkedList. + */ + +void* LinkedList_Last(wLinkedList* list) +{ + if (list->tail) + return list->tail->value; + else + return NULL; +} + +/** + * Methods + */ + +/** + * Determines whether the LinkedList contains a specific value. + */ + +BOOL LinkedList_Contains(wLinkedList* list, void* value) +{ + wLinkedListNode* item; + + if (!list->head) + return FALSE; + + item = list->head; + + while (item) + { + if (item->value == value) + break; + + item = item->next; + } + + return (item) ? TRUE : FALSE; +} + +/** + * Removes all entries from the LinkedList. + */ + +void LinkedList_Clear(wLinkedList* list) +{ + wLinkedListNode* node; + wLinkedListNode* nextNode; + + if (!list->head) + return; + + node = list->head; + + while (node) + { + nextNode = node->next; + free(node); + node = nextNode; + } + + list->head = list->tail = NULL; + list->count = 0; +} + +/** + * Adds a new node containing the specified value at the start of the LinkedList. + */ + +void LinkedList_AddFirst(wLinkedList* list, void* value) +{ + wLinkedListNode* node; + + node = (wLinkedListNode*) malloc(sizeof(wLinkedListNode)); + node->prev = node->next = NULL; + node->value = value; + + if (!list->head) + { + list->tail = list->head = node; + } + else + { + list->head->prev = node; + node->next = list->head; + list->head = node; + } + + list->count++; +} + +/** + * Adds a new node containing the specified value at the end of the LinkedList. + */ + +void LinkedList_AddLast(wLinkedList* list, void* value) +{ + wLinkedListNode* node; + + node = (wLinkedListNode*) malloc(sizeof(wLinkedListNode)); + node->prev = node->next = NULL; + node->value = value; + + if (!list->tail) + { + list->head = list->tail = node; + } + else + { + list->tail->next = node; + node->prev = list->tail; + list->tail = node; + } + + list->count++; +} + +/** + * Removes the first occurrence of the specified value from the LinkedList. + */ + +void LinkedList_Remove(wLinkedList* list, void* value) +{ + wLinkedListNode* node; + + node = list->head; + + while (node) + { + if (node->value == value) + { + if (node->prev) + node->prev->next = node->next; + + if (node->next) + node->next->prev = node->prev; + + if ((!node->prev) && (!node->next)) + list->head = list->tail = NULL; + + free(node); + + list->count--; + + break; + } + + node = node->next; + } +} + +/** + * Removes the node at the start of the LinkedList. + */ + +void LinkedList_RemoveFirst(wLinkedList* list) +{ + wLinkedListNode* node; + + if (list->head) + { + node = list->head; + + list->head = list->head->next; + + if (!list->head) + { + list->tail = NULL; + } + else + { + list->head->prev = NULL; + } + + free(node); + + list->count--; + } +} + +/** + * Removes the node at the end of the LinkedList. + */ + +void LinkedList_RemoveLast(wLinkedList* list) +{ + wLinkedListNode* node; + + if (list->tail) + { + node = list->tail; + + list->tail = list->tail->prev; + + if (!list->tail) + { + list->head = NULL; + } + else + { + list->tail->next = NULL; + } + + free(node); + + list->count--; + } +} + +/** + * Sets the enumerator to its initial position, which is before the first element in the collection. + */ + +void LinkedList_Enumerator_Reset(wLinkedList* list) +{ + list->initial = 1; + list->current = list->head; +} + +/* + * Gets the element at the current position of the enumerator. + */ + +void* LinkedList_Enumerator_Current(wLinkedList* list) +{ + if (list->initial) + return NULL; + + if (list->current) + return list->current->value; + else + return NULL; +} + +/* + * Advances the enumerator to the next element of the LinkedList. + */ + +BOOL LinkedList_Enumerator_MoveNext(wLinkedList* list) +{ + if (list->initial) + list->initial = 0; + else + list->current = list->current->next; + + if (!list->current) + return FALSE; + + return TRUE; +} + +/** + * Construction, Destruction + */ + +wLinkedList* LinkedList_New() +{ + wLinkedList* list = NULL; + + list = (wLinkedList*) malloc(sizeof(wLinkedList)); + + if (list) + { + list->count = 0; + list->initial = 0; + list->head = NULL; + list->tail = NULL; + list->current = NULL; + } + + return list; +} + +void LinkedList_Free(wLinkedList* list) +{ + if (list) + { + LinkedList_Clear(list); + free(list); + } +} + diff --git a/winpr/libwinpr/utils/collections/ListDictionary.c b/winpr/libwinpr/utils/collections/ListDictionary.c index 2216384a7..cb7ba420a 100644 --- a/winpr/libwinpr/utils/collections/ListDictionary.c +++ b/winpr/libwinpr/utils/collections/ListDictionary.c @@ -26,6 +26,8 @@ /** * C equivalent of the C# ListDictionary Class: * http://msdn.microsoft.com/en-us/library/system.collections.specialized.listdictionary.aspx + * + * Internal implementation uses a singly-linked list */ /** @@ -38,7 +40,27 @@ int ListDictionary_Count(wListDictionary* listDictionary) { - return 0; + int count = 0; + wListDictionaryItem* item; + + if (listDictionary->synchronized) + EnterCriticalSection(&listDictionary->lock); + + if (listDictionary->head) + { + item = listDictionary->head; + + while (item) + { + count++; + item = item->next; + } + } + + if (listDictionary->synchronized) + LeaveCriticalSection(&listDictionary->lock); + + return count; } /** @@ -78,7 +100,35 @@ BOOL ListDictionary_IsSynchronized(wListDictionary* listDictionary) void ListDictionary_Add(wListDictionary* listDictionary, void* key, void* value) { + wListDictionaryItem* item; + wListDictionaryItem* lastItem; + if (listDictionary->synchronized) + EnterCriticalSection(&listDictionary->lock); + + item = (wListDictionaryItem*) malloc(sizeof(wListDictionaryItem)); + + item->key = key; + item->value = value; + + item->next = NULL; + + if (!listDictionary->head) + { + listDictionary->head = item; + } + else + { + lastItem = listDictionary->head; + + while (lastItem->next) + lastItem = lastItem->next; + + lastItem->next = item; + } + + if (listDictionary->synchronized) + LeaveCriticalSection(&listDictionary->lock); } /** @@ -87,7 +137,28 @@ void ListDictionary_Add(wListDictionary* listDictionary, void* key, void* value) void ListDictionary_Clear(wListDictionary* listDictionary) { + wListDictionaryItem* item; + wListDictionaryItem* nextItem; + if (listDictionary->synchronized) + EnterCriticalSection(&listDictionary->lock); + + if (listDictionary->head) + { + item = listDictionary->head; + + while (item) + { + nextItem = item->next; + free(item); + item = nextItem; + } + + listDictionary->head = NULL; + } + + if (listDictionary->synchronized) + LeaveCriticalSection(&listDictionary->lock); } /** @@ -96,7 +167,31 @@ void ListDictionary_Clear(wListDictionary* listDictionary) BOOL ListDictionary_Contains(wListDictionary* listDictionary, void* key) { - return FALSE; + BOOL status = FALSE; + wListDictionaryItem* item; + + if (listDictionary->synchronized) + EnterCriticalSection(&listDictionary->lock); + + if (listDictionary->head) + { + item = listDictionary->head; + + while (item) + { + if (item->key == key) + break; + + item = item->next; + } + + status = (item) ? TRUE : FALSE; + } + + if (listDictionary->synchronized) + LeaveCriticalSection(&listDictionary->lock); + + return status; } /** @@ -105,7 +200,114 @@ BOOL ListDictionary_Contains(wListDictionary* listDictionary, void* key) void ListDictionary_Remove(wListDictionary* listDictionary, void* key) { + wListDictionaryItem* item; + wListDictionaryItem* prevItem; + if (listDictionary->synchronized) + EnterCriticalSection(&listDictionary->lock); + + if (listDictionary->head) + { + item = listDictionary->head; + + if (listDictionary->head->key == key) + { + listDictionary->head = listDictionary->head->next; + free(item); + } + else + { + if (item->next) + { + prevItem = item; + item = item->next; + + while (item) + { + if (item->key == key) + { + prevItem->next = item->next; + free(item); + break; + } + + item = item->next; + } + } + } + } + + if (listDictionary->synchronized) + LeaveCriticalSection(&listDictionary->lock); +} + +/** + * Get an item value using key + */ + +void* ListDictionary_GetItemValue(wListDictionary* listDictionary, void* key) +{ + void* value = NULL; + wListDictionaryItem* item; + + if (listDictionary->synchronized) + EnterCriticalSection(&listDictionary->lock); + + if (listDictionary->head) + { + item = listDictionary->head; + + while (item) + { + if (item->key == key) + break; + + item = item->next; + } + } + + value = (item) ? item->value : NULL; + + if (listDictionary->synchronized) + LeaveCriticalSection(&listDictionary->lock); + + return value; +} + +/** + * Set an item value using key + */ + +BOOL ListDictionary_SetItemValue(wListDictionary* listDictionary, void* key, void* value) +{ + BOOL status = FALSE; + wListDictionaryItem* item; + + if (listDictionary->synchronized) + EnterCriticalSection(&listDictionary->lock); + + if (listDictionary->head) + { + item = listDictionary->head; + + while (item) + { + if (item->key == key) + break; + + item = item->next; + } + + if (item) + item->value = value; + + status = (item) ? TRUE : FALSE; + } + + if (listDictionary->synchronized) + LeaveCriticalSection(&listDictionary->lock); + + return status; } /** @@ -121,6 +323,10 @@ wListDictionary* ListDictionary_New(BOOL synchronized) if (listDictionary) { listDictionary->synchronized = synchronized; + + listDictionary->head = NULL; + + InitializeCriticalSectionAndSpinCount(&listDictionary->lock, 4000); } return listDictionary; @@ -128,6 +334,11 @@ wListDictionary* ListDictionary_New(BOOL synchronized) void ListDictionary_Free(wListDictionary* listDictionary) { - free(listDictionary); + if (listDictionary) + { + ListDictionary_Clear(listDictionary); + DeleteCriticalSection(&listDictionary->lock); + free(listDictionary); + } } diff --git a/winpr/libwinpr/utils/collections/MessageQueue.c b/winpr/libwinpr/utils/collections/MessageQueue.c index d13916922..e7b8a5e84 100644 --- a/winpr/libwinpr/utils/collections/MessageQueue.c +++ b/winpr/libwinpr/utils/collections/MessageQueue.c @@ -69,7 +69,7 @@ BOOL MessageQueue_Wait(wMessageQueue* queue) void MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message) { - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size == queue->capacity) { @@ -100,7 +100,7 @@ void MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message) if (queue->size > 0) SetEvent(queue->event); - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); } void MessageQueue_Post(wMessageQueue* queue, void* context, UINT32 type, void* wParam, void* lParam) @@ -127,7 +127,7 @@ int MessageQueue_Get(wMessageQueue* queue, wMessage* message) if (!MessageQueue_Wait(queue)) return status; - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size > 0) { @@ -142,7 +142,7 @@ int MessageQueue_Get(wMessageQueue* queue, wMessage* message) status = (message->id != WMQ_QUIT) ? 1 : 0; } - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return status; } @@ -151,7 +151,7 @@ int MessageQueue_Peek(wMessageQueue* queue, wMessage* message, BOOL remove) { int status = 0; - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size > 0) { @@ -169,7 +169,7 @@ int MessageQueue_Peek(wMessageQueue* queue, wMessage* message, BOOL remove) } } - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return status; } @@ -194,7 +194,7 @@ wMessageQueue* MessageQueue_New() queue->array = (wMessage*) malloc(sizeof(wMessage) * queue->capacity); ZeroMemory(queue->array, sizeof(wMessage) * queue->capacity); - queue->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&queue->lock, 4000); queue->event = CreateEvent(NULL, TRUE, FALSE, NULL); } @@ -204,7 +204,7 @@ wMessageQueue* MessageQueue_New() void MessageQueue_Free(wMessageQueue* queue) { CloseHandle(queue->event); - CloseHandle(queue->mutex); + DeleteCriticalSection(&queue->lock); free(queue->array); free(queue); diff --git a/winpr/libwinpr/utils/collections/ObjectPool.c b/winpr/libwinpr/utils/collections/ObjectPool.c index 472eba1d2..bca31edfd 100644 --- a/winpr/libwinpr/utils/collections/ObjectPool.c +++ b/winpr/libwinpr/utils/collections/ObjectPool.c @@ -43,7 +43,7 @@ void* ObjectPool_Take(wObjectPool* pool) void* obj = NULL; if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if (pool->size > 0) obj = pool->array[--(pool->size)]; @@ -54,8 +54,11 @@ void* ObjectPool_Take(wObjectPool* pool) obj = pool->object.fnObjectNew(); } + if (pool->object.fnObjectInit) + pool->object.fnObjectInit(obj); + if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); return obj; } @@ -67,7 +70,7 @@ void* ObjectPool_Take(wObjectPool* pool) void ObjectPool_Return(wObjectPool* pool, void* obj) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if ((pool->size + 1) >= pool->capacity) { @@ -77,8 +80,11 @@ void ObjectPool_Return(wObjectPool* pool, void* obj) pool->array[(pool->size)++] = obj; + if (pool->object.fnObjectUninit) + pool->object.fnObjectUninit(obj); + if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -88,7 +94,7 @@ void ObjectPool_Return(wObjectPool* pool, void* obj) void ObjectPool_Clear(wObjectPool* pool) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); while (pool->size > 0) { @@ -99,7 +105,7 @@ void ObjectPool_Clear(wObjectPool* pool) } if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -119,7 +125,7 @@ wObjectPool* ObjectPool_New(BOOL synchronized) pool->synchronized = synchronized; if (pool->synchronized) - pool->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&pool->lock, 4000); pool->size = 0; pool->capacity = 32; @@ -136,7 +142,7 @@ void ObjectPool_Free(wObjectPool* pool) ObjectPool_Clear(pool); if (pool->synchronized) - CloseHandle(pool->mutex); + DeleteCriticalSection(&pool->lock); free(pool->array); diff --git a/winpr/libwinpr/utils/collections/PubSub.c b/winpr/libwinpr/utils/collections/PubSub.c index 160a0ddf0..abd29098c 100644 --- a/winpr/libwinpr/utils/collections/PubSub.c +++ b/winpr/libwinpr/utils/collections/PubSub.c @@ -46,14 +46,14 @@ wEventType* PubSub_GetEventTypes(wPubSub* pubSub, int* count) * Methods */ -BOOL PubSub_Lock(wPubSub* pubSub) +void PubSub_Lock(wPubSub* pubSub) { - return (WaitForSingleObject(pubSub->mutex, INFINITE) == WAIT_OBJECT_0) ? TRUE : FALSE; + EnterCriticalSection(&pubSub->lock); } -BOOL PubSub_Unlock(wPubSub* pubSub) +void PubSub_Unlock(wPubSub* pubSub) { - return ReleaseMutex(pubSub->mutex); + LeaveCriticalSection(&pubSub->lock); } wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName) @@ -167,6 +167,9 @@ int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, wEvent event = PubSub_FindEventType(pubSub, EventName); + if (pubSub->synchronized) + PubSub_Unlock(pubSub); + if (event) { status = 0; @@ -181,9 +184,6 @@ int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, wEvent } } - if (pubSub->synchronized) - PubSub_Unlock(pubSub); - return status; } @@ -202,7 +202,7 @@ wPubSub* PubSub_New(BOOL synchronized) pubSub->synchronized = synchronized; if (pubSub->synchronized) - pubSub->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&pubSub->lock, 4000); pubSub->count = 0; pubSub->size = 64; @@ -219,7 +219,7 @@ void PubSub_Free(wPubSub* pubSub) if (pubSub) { if (pubSub->synchronized) - CloseHandle(pubSub->mutex); + DeleteCriticalSection(&pubSub->lock); if (pubSub->events) free(pubSub->events); diff --git a/winpr/libwinpr/utils/collections/Queue.c b/winpr/libwinpr/utils/collections/Queue.c index fa33df76a..7a729622e 100644 --- a/winpr/libwinpr/utils/collections/Queue.c +++ b/winpr/libwinpr/utils/collections/Queue.c @@ -47,18 +47,18 @@ int Queue_Count(wQueue* queue) * Lock access to the ArrayList */ -BOOL Queue_Lock(wQueue* queue) +void Queue_Lock(wQueue* queue) { - return (WaitForSingleObject(queue->mutex, INFINITE) == WAIT_OBJECT_0) ? TRUE : FALSE; + EnterCriticalSection(&queue->lock); } /** * Unlock access to the ArrayList */ -BOOL Queue_Unlock(wQueue* queue) +void Queue_Unlock(wQueue* queue) { - return ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); } /** @@ -83,7 +83,7 @@ void Queue_Clear(wQueue* queue) int index; if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); for (index = queue->head; index != queue->tail; index = (index + 1) % queue->capacity) { @@ -97,7 +97,7 @@ void Queue_Clear(wQueue* queue) queue->head = queue->tail = 0; if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); } /** @@ -110,7 +110,7 @@ BOOL Queue_Contains(wQueue* queue, void* obj) BOOL found = FALSE; if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); for (index = 0; index < queue->tail; index++) { @@ -122,7 +122,7 @@ BOOL Queue_Contains(wQueue* queue, void* obj) } if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return found; } @@ -134,7 +134,7 @@ BOOL Queue_Contains(wQueue* queue, void* obj) void Queue_Enqueue(wQueue* queue, void* obj) { if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size == queue->capacity) { @@ -162,7 +162,7 @@ void Queue_Enqueue(wQueue* queue, void* obj) SetEvent(queue->event); if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); } /** @@ -174,7 +174,7 @@ void* Queue_Dequeue(wQueue* queue) void* obj = NULL; if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size > 0) { @@ -188,7 +188,7 @@ void* Queue_Dequeue(wQueue* queue) ResetEvent(queue->event); if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return obj; } @@ -202,13 +202,13 @@ void* Queue_Peek(wQueue* queue) void* obj = NULL; if (queue->synchronized) - WaitForSingleObject(queue->mutex, INFINITE); + EnterCriticalSection(&queue->lock); if (queue->size > 0) obj = queue->array[queue->head]; if (queue->synchronized) - ReleaseMutex(queue->mutex); + LeaveCriticalSection(&queue->lock); return obj; } @@ -243,7 +243,7 @@ wQueue* Queue_New(BOOL synchronized, int capacity, int growthFactor) queue->array = (void**) malloc(sizeof(void*) * queue->capacity); ZeroMemory(queue->array, sizeof(void*) * queue->capacity); - queue->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&queue->lock, 4000); queue->event = CreateEvent(NULL, TRUE, FALSE, NULL); ZeroMemory(&queue->object, sizeof(wObject)); @@ -257,7 +257,7 @@ void Queue_Free(wQueue* queue) Queue_Clear(queue); CloseHandle(queue->event); - CloseHandle(queue->mutex); + DeleteCriticalSection(&queue->lock); free(queue->array); free(queue); } diff --git a/winpr/libwinpr/utils/collections/Reference.c b/winpr/libwinpr/utils/collections/Reference.c index 7df1c84b2..171123661 100644 --- a/winpr/libwinpr/utils/collections/Reference.c +++ b/winpr/libwinpr/utils/collections/Reference.c @@ -88,7 +88,7 @@ UINT32 ReferenceTable_Add(wReferenceTable* referenceTable, void* ptr) wReference* reference = NULL; if (referenceTable->synchronized) - WaitForSingleObject(referenceTable->mutex, INFINITE); + EnterCriticalSection(&referenceTable->lock); reference = ReferenceTable_FindEntry(referenceTable, ptr); @@ -102,7 +102,7 @@ UINT32 ReferenceTable_Add(wReferenceTable* referenceTable, void* ptr) count = ++(reference->Count); if (referenceTable->synchronized) - ReleaseMutex(referenceTable->mutex); + LeaveCriticalSection(&referenceTable->lock); return count; } @@ -113,7 +113,7 @@ UINT32 ReferenceTable_Release(wReferenceTable* referenceTable, void* ptr) wReference* reference = NULL; if (referenceTable->synchronized) - WaitForSingleObject(referenceTable->mutex, INFINITE); + EnterCriticalSection(&referenceTable->lock); reference = ReferenceTable_FindEntry(referenceTable, ptr); @@ -133,7 +133,7 @@ UINT32 ReferenceTable_Release(wReferenceTable* referenceTable, void* ptr) } if (referenceTable->synchronized) - ReleaseMutex(referenceTable->mutex); + LeaveCriticalSection(&referenceTable->lock); return count; } @@ -154,7 +154,7 @@ wReferenceTable* ReferenceTable_New(BOOL synchronized, void* context, REFERENCE_ ZeroMemory(referenceTable->array, sizeof(wReference) * referenceTable->size); referenceTable->synchronized = synchronized; - referenceTable->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&referenceTable->lock, 4000); } return referenceTable; @@ -164,7 +164,7 @@ void ReferenceTable_Free(wReferenceTable* referenceTable) { if (referenceTable) { - CloseHandle(referenceTable->mutex); + DeleteCriticalSection(&referenceTable->lock); free(referenceTable->array); free(referenceTable); } diff --git a/winpr/libwinpr/utils/collections/Stack.c b/winpr/libwinpr/utils/collections/Stack.c index 383fe0de1..5ddb18088 100644 --- a/winpr/libwinpr/utils/collections/Stack.c +++ b/winpr/libwinpr/utils/collections/Stack.c @@ -84,7 +84,7 @@ BOOL Stack_Contains(wStack* stack, void* obj) void Stack_Push(wStack* stack, void* obj) { if (stack->synchronized) - WaitForSingleObject(stack->mutex, INFINITE); + EnterCriticalSection(&stack->lock); if ((stack->size + 1) >= stack->capacity) { @@ -95,7 +95,7 @@ void Stack_Push(wStack* stack, void* obj) stack->array[(stack->size)++] = obj; if (stack->synchronized) - ReleaseMutex(stack->mutex); + LeaveCriticalSection(&stack->lock); } /** @@ -107,13 +107,13 @@ void* Stack_Pop(wStack* stack) void* obj = NULL; if (stack->synchronized) - WaitForSingleObject(stack->mutex, INFINITE); + EnterCriticalSection(&stack->lock); if (stack->size > 0) obj = stack->array[--(stack->size)]; if (stack->synchronized) - ReleaseMutex(stack->mutex); + LeaveCriticalSection(&stack->lock); return obj; } @@ -127,13 +127,13 @@ void* Stack_Peek(wStack* stack) void* obj = NULL; if (stack->synchronized) - WaitForSingleObject(stack->mutex, INFINITE); + EnterCriticalSection(&stack->lock); if (stack->size > 0) obj = stack->array[stack->size]; if (stack->synchronized) - ReleaseMutex(stack->mutex); + LeaveCriticalSection(&stack->lock); return obj; } @@ -153,7 +153,7 @@ wStack* Stack_New(BOOL synchronized) stack->synchronized = synchronized; if (stack->synchronized) - stack->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&stack->lock, 4000); stack->size = 0; stack->capacity = 32; @@ -168,7 +168,7 @@ void Stack_Free(wStack* stack) if (stack) { if (stack->synchronized) - CloseHandle(stack->mutex); + DeleteCriticalSection(&stack->lock); free(stack->array); diff --git a/winpr/libwinpr/utils/collections/StreamPool.c b/winpr/libwinpr/utils/collections/StreamPool.c index 1605c5332..dab11c0e2 100644 --- a/winpr/libwinpr/utils/collections/StreamPool.c +++ b/winpr/libwinpr/utils/collections/StreamPool.c @@ -44,7 +44,8 @@ void StreamPool_ShiftUsed(wStreamPool* pool, int index, int count) } else if (count < 0) { - MoveMemory(&pool->uArray[index], &pool->uArray[index - count], (pool->uSize - index) * sizeof(wStream*)); + if (pool->uSize - index + count > 0) + MoveMemory(&pool->uArray[index], &pool->uArray[index - count], (pool->uSize - index + count) * sizeof(wStream*)); pool->uSize += count; } } @@ -101,7 +102,8 @@ void StreamPool_ShiftAvailable(wStreamPool* pool, int index, int count) } else if (count < 0) { - MoveMemory(&pool->aArray[index], &pool->aArray[index - count], (pool->aSize - index) * sizeof(wStream*)); + if (pool->aSize - index + count > 0) + MoveMemory(&pool->aArray[index], &pool->aArray[index - count], (pool->aSize - index + count) * sizeof(wStream*)); pool->aSize += count; } } @@ -118,7 +120,7 @@ wStream* StreamPool_Take(wStreamPool* pool, size_t size) BOOL found = FALSE; if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if (size == 0) size = pool->defaultSize; @@ -153,7 +155,7 @@ wStream* StreamPool_Take(wStreamPool* pool, size_t size) StreamPool_AddUsed(pool, s); if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); return s; } @@ -165,7 +167,7 @@ wStream* StreamPool_Take(wStreamPool* pool, size_t size) void StreamPool_Return(wStreamPool* pool, wStream* s) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); if ((pool->aSize + 1) >= pool->aCapacity) { @@ -177,7 +179,7 @@ void StreamPool_Return(wStreamPool* pool, wStream* s) StreamPool_RemoveUsed(pool, s); if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -186,7 +188,7 @@ void StreamPool_Return(wStreamPool* pool, wStream* s) void StreamPool_Lock(wStreamPool* pool) { - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); } /** @@ -195,7 +197,7 @@ void StreamPool_Lock(wStreamPool* pool) void StreamPool_Unlock(wStreamPool* pool) { - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -241,7 +243,7 @@ wStream* StreamPool_Find(wStreamPool* pool, BYTE* ptr) wStream* s = NULL; BOOL found = FALSE; - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); for (index = 0; index < pool->uSize; index++) { @@ -254,7 +256,7 @@ wStream* StreamPool_Find(wStreamPool* pool, BYTE* ptr) } } - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); return (found) ? s : NULL; } @@ -294,7 +296,7 @@ void StreamPool_Release(wStreamPool* pool, BYTE* ptr) void StreamPool_Clear(wStreamPool* pool) { if (pool->synchronized) - WaitForSingleObject(pool->mutex, INFINITE); + EnterCriticalSection(&pool->lock); while (pool->aSize > 0) { @@ -303,7 +305,7 @@ void StreamPool_Clear(wStreamPool* pool) } if (pool->synchronized) - ReleaseMutex(pool->mutex); + LeaveCriticalSection(&pool->lock); } /** @@ -323,8 +325,7 @@ wStreamPool* StreamPool_New(BOOL synchronized, size_t defaultSize) pool->synchronized = synchronized; pool->defaultSize = defaultSize; - if (pool->synchronized) - pool->mutex = CreateMutex(NULL, FALSE, NULL); + InitializeCriticalSectionAndSpinCount(&pool->lock, 4000); pool->aSize = 0; pool->aCapacity = 32; @@ -344,8 +345,7 @@ void StreamPool_Free(wStreamPool* pool) { StreamPool_Clear(pool); - if (pool->synchronized) - CloseHandle(pool->mutex); + DeleteCriticalSection(&pool->lock); free(pool->aArray); free(pool->uArray); diff --git a/winpr/libwinpr/utils/test/CMakeLists.txt b/winpr/libwinpr/utils/test/CMakeLists.txt index 2656109b0..31d1de762 100644 --- a/winpr/libwinpr/utils/test/CMakeLists.txt +++ b/winpr/libwinpr/utils/test/CMakeLists.txt @@ -9,7 +9,10 @@ set(${MODULE_PREFIX}_TESTS TestPrint.c TestPubSub.c TestArrayList.c + TestLinkedList.c + TestListDictionary.c TestCmdLine.c + TestBufferPool.c TestStreamPool.c TestMessageQueue.c TestMessagePipe.c) diff --git a/winpr/libwinpr/utils/test/TestBufferPool.c b/winpr/libwinpr/utils/test/TestBufferPool.c new file mode 100644 index 000000000..710bc61dd --- /dev/null +++ b/winpr/libwinpr/utils/test/TestBufferPool.c @@ -0,0 +1,78 @@ + +#include +#include +#include + +int TestBufferPool(int argc, char* argv[]) +{ + int PoolSize; + int BufferSize; + int DefaultSize; + wBufferPool* pool; + BYTE* Buffers[10]; + + DefaultSize = 1234; + + pool = BufferPool_New(TRUE, DefaultSize, 16); + + Buffers[0] = BufferPool_Take(pool, -1); + Buffers[1] = BufferPool_Take(pool, 0); + Buffers[2] = BufferPool_Take(pool, 2048); + + PoolSize = BufferPool_GetPoolSize(pool); + + if (PoolSize != 3) + { + printf("BufferPool_GetPoolSize failure: Actual: %d Expected: %d\n", PoolSize, 3); + return -1; + } + + BufferSize = BufferPool_GetBufferSize(pool, Buffers[0]); + + if (BufferSize != DefaultSize) + { + printf("BufferPool_GetBufferSize failure: Actual: %d Expected: %d\n", BufferSize, DefaultSize); + return -1; + } + + BufferSize = BufferPool_GetBufferSize(pool, Buffers[1]); + + if (BufferSize != DefaultSize) + { + printf("BufferPool_GetBufferSize failure: Actual: %d Expected: %d\n", BufferSize, DefaultSize); + return -1; + } + + BufferSize = BufferPool_GetBufferSize(pool, Buffers[2]); + + if (BufferSize != 2048) + { + printf("BufferPool_GetBufferSize failure: Actual: %d Expected: %d\n", BufferSize, 2048); + return -1; + } + + BufferPool_Return(pool, Buffers[1]); + + PoolSize = BufferPool_GetPoolSize(pool); + + if (PoolSize != 2) + { + printf("BufferPool_GetPoolSize failure: Actual: %d Expected: %d\n", PoolSize, 2); + return -1; + } + + BufferPool_Clear(pool); + + PoolSize = BufferPool_GetPoolSize(pool); + + if (PoolSize != 0) + { + printf("BufferPool_GetPoolSize failure: Actual: %d Expected: %d\n", PoolSize, 0); + return -1; + } + + BufferPool_Free(pool); + + return 0; +} + diff --git a/winpr/libwinpr/utils/test/TestLinkedList.c b/winpr/libwinpr/utils/test/TestLinkedList.c new file mode 100644 index 000000000..555d617e7 --- /dev/null +++ b/winpr/libwinpr/utils/test/TestLinkedList.c @@ -0,0 +1,114 @@ + +#include +#include +#include + +int TestLinkedList(int argc, char* argv[]) +{ + int count; + int number; + wLinkedList* list; + + list = LinkedList_New(); + + LinkedList_AddFirst(list, (void*) (size_t) 1); + LinkedList_AddLast(list, (void*) (size_t) 2); + LinkedList_AddLast(list, (void*) (size_t) 3); + + count = LinkedList_Count(list); + + if (count != 3) + { + printf("LinkedList_Count: expected %d, actual: %d\n", 3, count); + return -1; + } + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + + printf("LinkedList First: %d Last: %d\n", + (int) (size_t) LinkedList_First(list), (int) (size_t) LinkedList_Last(list)); + + LinkedList_RemoveFirst(list); + LinkedList_RemoveLast(list); + + count = LinkedList_Count(list); + + if (count != 1) + { + printf("LinkedList_Count: expected %d, actual: %d\n", 1, count); + return -1; + } + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + + printf("LinkedList First: %d Last: %d\n", + (int) (size_t) LinkedList_First(list), (int) (size_t) LinkedList_Last(list)); + + LinkedList_RemoveFirst(list); + LinkedList_RemoveLast(list); + + count = LinkedList_Count(list); + + if (count != 0) + { + printf("LinkedList_Count: expected %d, actual: %d\n", 0, count); + return -1; + } + + LinkedList_AddFirst(list, (void*) (size_t) 4); + LinkedList_AddLast(list, (void*) (size_t) 5); + LinkedList_AddLast(list, (void*) (size_t) 6); + + count = LinkedList_Count(list); + + if (count != 3) + { + printf("LinkedList_Count: expected %d, actual: %d\n", 3, count); + return -1; + } + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + + printf("LinkedList First: %d Last: %d\n", + (int) (size_t) LinkedList_First(list), (int) (size_t) LinkedList_Last(list)); + + LinkedList_Remove(list, (void*) (size_t) 5); + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + number = (int) (size_t) LinkedList_Enumerator_Current(list); + printf("\t%d\n", number); + } + printf("\n"); + + printf("LinkedList First: %d Last: %d\n", + (int) (size_t) LinkedList_First(list), (int) (size_t) LinkedList_Last(list)); + + LinkedList_Free(list); + + return 0; +} + diff --git a/winpr/libwinpr/utils/test/TestListDictionary.c b/winpr/libwinpr/utils/test/TestListDictionary.c new file mode 100644 index 000000000..c47ec3f5b --- /dev/null +++ b/winpr/libwinpr/utils/test/TestListDictionary.c @@ -0,0 +1,130 @@ + +#include +#include +#include + +static char* key1 = "key1"; +static char* key2 = "key2"; +static char* key3 = "key3"; + +static char* val1 = "val1"; +static char* val2 = "val2"; +static char* val3 = "val3"; + +int TestListDictionary(int argc, char* argv[]) +{ + int count; + char* value; + wListDictionary* list; + + list = ListDictionary_New(TRUE); + + ListDictionary_Add(list, key1, val1); + ListDictionary_Add(list, key2, val2); + ListDictionary_Add(list, key3, val3); + + count = ListDictionary_Count(list); + + if (count != 3) + { + printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 3, count); + return -1; + } + + ListDictionary_Remove(list, key2); + + count = ListDictionary_Count(list); + + if (count != 2) + { + printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 2, count); + return -1; + } + + ListDictionary_Remove(list, key3); + + count = ListDictionary_Count(list); + + if (count != 1) + { + printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 1, count); + return -1; + } + + ListDictionary_Remove(list, key1); + + count = ListDictionary_Count(list); + + if (count != 0) + { + printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 0, count); + return -1; + } + + ListDictionary_Add(list, key1, val1); + ListDictionary_Add(list, key2, val2); + ListDictionary_Add(list, key3, val3); + + count = ListDictionary_Count(list); + + if (count != 3) + { + printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 3, count); + return -1; + } + + value = (char*) ListDictionary_GetItemValue(list, key1); + + if (strcmp(value, val1) != 0) + { + printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", val1, value); + return -1; + } + + value = (char*) ListDictionary_GetItemValue(list, key2); + + if (strcmp(value, val2) != 0) + { + printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", val2, value); + return -1; + } + + value = (char*) ListDictionary_GetItemValue(list, key3); + + if (strcmp(value, val3) != 0) + { + printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", val3, value); + return -1; + } + + ListDictionary_SetItemValue(list, key2, "apple"); + + value = (char*) ListDictionary_GetItemValue(list, key2); + + if (strcmp(value, "apple") != 0) + { + printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", "apple", value); + return -1; + } + + if (!ListDictionary_Contains(list, key2)) + { + printf("ListDictionary_Contains: Expected : %d, Actual: %d\n", TRUE, FALSE); + return -1; + } + + ListDictionary_Clear(list); + + count = ListDictionary_Count(list); + + if (count != 0) + { + printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 0, count); + return -1; + } + + ListDictionary_Free(list); + + return 0; +} + diff --git a/winpr/tools/makecert/CMakeLists.txt b/winpr/tools/makecert/CMakeLists.txt index 7663caa18..c31d08cef 100644 --- a/winpr/tools/makecert/CMakeLists.txt +++ b/winpr/tools/makecert/CMakeLists.txt @@ -38,8 +38,10 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) -add_subdirectory(cli) +if(NOT WITH_WAYK) + install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) + add_subdirectory(cli) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Tools")