From 1aaad2c68f49c027f8414de65361763e9adcc9b5 Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Mon, 14 Feb 2022 08:03:24 +0100 Subject: [PATCH 1/2] New upstream version 2.5.0+dfsg1 --- CMakeLists.txt | 2 +- ChangeLog | 22 ++ .../audin/client/opensles/audin_opensl_es.c | 2 +- channels/client/addin.c | 83 ++++- channels/disp/server/disp_main.c | 2 +- channels/rdpei/client/rdpei_main.c | 1 - client/Wayland/wlf_cliprdr.c | 43 ++- client/Wayland/wlfreerdp.c | 9 +- include/freerdp/locale/locale.h | 4 + include/freerdp/settings.h | 33 +- include/freerdp/update.h | 1 + libfreerdp/common/settings_getters.c | 7 + libfreerdp/common/settings_str.c | 1 + libfreerdp/core/gateway/ncacn_http.c | 4 +- libfreerdp/core/gateway/rdg.c | 2 +- libfreerdp/core/info.c | 4 +- libfreerdp/core/nego.c | 14 +- libfreerdp/core/settings.c | 12 +- libfreerdp/core/tcp.c | 6 +- .../core/test/settings_property_lists.h | 1 + libfreerdp/core/update.c | 6 +- libfreerdp/crypto/tls.c | 9 +- libfreerdp/locale/CMakeLists.txt | 10 + libfreerdp/locale/keyboard.c | 11 +- libfreerdp/locale/keyboard_apple.c | 244 ++++++++++++++ libfreerdp/locale/keyboard_apple.h | 28 ++ libfreerdp/locale/locale.c | 203 ++++++++---- libfreerdp/utils/signal.c | 10 +- winpr/CMakeLists.txt | 2 +- winpr/libwinpr/crypto/cipher.c | 8 - winpr/libwinpr/registry/registry.c | 58 +++- winpr/libwinpr/registry/registry_reg.c | 307 +++++++++++------- winpr/libwinpr/registry/registry_reg.h | 5 +- winpr/libwinpr/utils/ssl.c | 20 +- 34 files changed, 890 insertions(+), 284 deletions(-) create mode 100644 libfreerdp/locale/keyboard_apple.c create mode 100644 libfreerdp/locale/keyboard_apple.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a068702..22c0347 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.4.1") +set(RAW_VERSION_STRING "2.5.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index 2662383..bf4e500 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +# 2022-01-12 Version 2.5.0 + +Noteworthy changes: +* Fixed smartcard login in case a redirection occurs the pin was lost +* Backported windows client drawing fixes +* Backported improved macOS keyboard layout detection +* Backported TcpConnectTimeout +* Backported LibreSSL compatibility patches +* Backported signal handler backtrace +* Backported OpenSSL 3.0 support + +Fixed issues: +* Backport #7539: Wayland client clipboard issues +* Backport #7509: Various fixes regarding registry emulation, addin loader + and updated locale detection +* Backport #7466: Android android_register_pointer missing initialization + +Important notes: + +For a complete and detailed change log since the last release run: +git log 2.4.1..2.5.0 + # 2021-10-20 Version 2.4.1 Noteworthy changes: diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index 4e3efde..87393ad 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -248,7 +248,7 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, ADDIN_A { UINT status; DWORD flags; - COMMAND_LINE_ARGUMENT_A* arg; + const COMMAND_LINE_ARGUMENT_A* arg; AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device; COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, diff --git a/channels/client/addin.c b/channels/client/addin.c index cd6f90e..db32ff8 100644 --- a/channels/client/addin.c +++ b/channels/client/addin.c @@ -231,10 +231,8 @@ static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCS do { - char* p[5]; - FREERDP_ADDIN* pAddin; - nDashes = 0; - pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN)); + BOOL used = FALSE; + FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN)); if (!pAddin) { @@ -242,57 +240,116 @@ static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCS goto error_out; } + nDashes = 0; for (index = 0; FindData.cFileName[index]; index++) nDashes += (FindData.cFileName[index] == '-') ? 1 : 0; if (nDashes == 1) { + size_t len; + char* p[2] = { 0 }; /* -client. */ p[0] = FindData.cFileName; p[1] = strchr(p[0], '-') + 1; - strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1); + + len = p[1] - p[0]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1)); + pAddin->dwFlags = FREERDP_ADDIN_CLIENT; pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC; pAddin->dwFlags |= FREERDP_ADDIN_NAME; ppAddins[nAddins++] = pAddin; + + used = TRUE; } else if (nDashes == 2) { + size_t len; + char* p[4] = { 0 }; /* -client-. */ p[0] = FindData.cFileName; p[1] = strchr(p[0], '-') + 1; p[2] = strchr(p[1], '-') + 1; p[3] = strchr(p[2], '.') + 1; - strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1); - strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1); + + len = p[1] - p[0]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1)); + + len = p[3] - p[2]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1)); + pAddin->dwFlags = FREERDP_ADDIN_CLIENT; pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC; pAddin->dwFlags |= FREERDP_ADDIN_NAME; pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM; ppAddins[nAddins++] = pAddin; + + used = TRUE; } else if (nDashes == 3) { + size_t len; + char* p[5] = { 0 }; /* -client--. */ p[0] = FindData.cFileName; p[1] = strchr(p[0], '-') + 1; p[2] = strchr(p[1], '-') + 1; p[3] = strchr(p[2], '-') + 1; p[4] = strchr(p[3], '.') + 1; - strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1); - strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1); - strncpy(pAddin->cType, p[3], (p[4] - p[3]) - 1); + + len = p[1] - p[0]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1)); + + len = p[3] - p[2]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1)); + + len = p[4] - p[3]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cType, p[3], MIN(ARRAYSIZE(pAddin->cType), len - 1)); + pAddin->dwFlags = FREERDP_ADDIN_CLIENT; pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC; pAddin->dwFlags |= FREERDP_ADDIN_NAME; pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM; pAddin->dwFlags |= FREERDP_ADDIN_TYPE; ppAddins[nAddins++] = pAddin; + + used = TRUE; } - else - { + + skip: + if (!used) free(pAddin); - } + } while (FindNextFileA(hFind, &FindData)); FindClose(hFind); diff --git a/channels/disp/server/disp_main.c b/channels/disp/server/disp_main.c index 5340165..a764acd 100644 --- a/channels/disp/server/disp_main.c +++ b/channels/disp/server/disp_main.c @@ -58,7 +58,7 @@ static wStream* disp_server_single_packet_new(UINT32 type, UINT32 length) } header.type = type; - header.length = length; + header.length = DISPLAY_CONTROL_HEADER_LENGTH + length; if ((error = disp_write_header(s, &header))) { diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index f20d58a..1d95054 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -1386,7 +1386,6 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) return CHANNEL_RC_OK; error_out: free(context); - free(rdpei->contactPoints); free(rdpei); return error; } diff --git a/client/Wayland/wlf_cliprdr.c b/client/Wayland/wlf_cliprdr.c index 0762cfa..0f0195d 100644 --- a/client/Wayland/wlf_cliprdr.c +++ b/client/Wayland/wlf_cliprdr.c @@ -80,6 +80,7 @@ struct wlf_clipboard FILE* responseFile; UINT32 responseFormat; const char* responseMime; + CRITICAL_SECTION lock; }; static BOOL wlf_mime_is_text(const char* mime) @@ -275,7 +276,7 @@ BOOL wlf_cliprdr_handle_event(wfClipboard* clipboard, const UwacClipboardEvent* return TRUE; case UWAC_EVENT_CLIPBOARD_OFFER: - WLog_Print(clipboard->log, WLOG_INFO, "client announces mime %s", event->mime); + WLog_Print(clipboard->log, WLOG_DEBUG, "client announces mime %s", event->mime); wlf_cliprdr_add_client_format(clipboard, event->mime); return TRUE; @@ -387,6 +388,8 @@ static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* wfClipboard* clipboard = (wfClipboard*)context; size_t x; WINPR_UNUSED(seat); + + EnterCriticalSection(&clipboard->lock); clipboard->responseMime = NULL; for (x = 0; x < ARRAYSIZE(mime_html); x++) @@ -427,6 +430,8 @@ static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* if (clipboard->responseMime != NULL) { + if (clipboard->responseFile != NULL) + fclose(clipboard->responseFile); clipboard->responseFile = fdopen(fd, "w"); if (clipboard->responseFile) @@ -436,6 +441,7 @@ static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* "failed to open clipboard file descriptor for MIME %s", clipboard->responseMime); } + LeaveCriticalSection(&clipboard->lock); } static void wlf_cliprdr_cancel_data(UwacSeat* seat, void* context) @@ -673,6 +679,8 @@ wlf_cliprdr_server_format_data_response(CliprdrClientContext* context, const WCHAR* wdata = (const WCHAR*)formatDataResponse->requestedFormatData; wfClipboard* clipboard = (wfClipboard*)context->custom; + EnterCriticalSection(&clipboard->lock); + if (size > INT_MAX * sizeof(WCHAR)) return ERROR_INTERNAL_ERROR; @@ -694,10 +702,16 @@ wlf_cliprdr_server_format_data_response(CliprdrClientContext* context, break; } - fwrite(data, 1, size, clipboard->responseFile); - fclose(clipboard->responseFile); + if (clipboard->responseFile) + { + fwrite(data, 1, size, clipboard->responseFile); + fclose(clipboard->responseFile); + clipboard->responseFile = NULL; + } rc = CHANNEL_RC_OK; free(cdata); + + LeaveCriticalSection(&clipboard->lock); return rc; } @@ -829,17 +843,24 @@ static UINT wlf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegat wfClipboard* wlf_clipboard_new(wlfContext* wfc) { rdpChannels* channels; - wfClipboard* clipboard; + wfClipboard* clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard)); - if (!(clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard)))) - return NULL; + if (!clipboard) + goto fail; + InitializeCriticalSection(&clipboard->lock); clipboard->wfc = wfc; channels = wfc->context.channels; clipboard->log = WLog_Get(TAG); clipboard->channels = channels; clipboard->system = ClipboardCreate(); + if (!clipboard->system) + goto fail; + clipboard->delegate = ClipboardGetDelegate(clipboard->system); + if (!clipboard->delegate) + goto fail; + clipboard->delegate->custom = clipboard; /* TODO: set up a filesystem base path for local URI */ /* clipboard->delegate->basePath = "file:///tmp/foo/bar/gaga"; */ @@ -848,6 +869,10 @@ wfClipboard* wlf_clipboard_new(wlfContext* wfc) clipboard->delegate->ClipboardFileRangeSuccess = wlf_cliprdr_clipboard_file_range_success; clipboard->delegate->ClipboardFileRangeFailure = wlf_cliprdr_clipboard_file_range_failure; return clipboard; + +fail: + wlf_clipboard_free(clipboard); + return NULL; } void wlf_clipboard_free(wfClipboard* clipboard) @@ -858,6 +883,12 @@ void wlf_clipboard_free(wfClipboard* clipboard) wlf_cliprdr_free_server_formats(clipboard); wlf_cliprdr_free_client_formats(clipboard); ClipboardDestroy(clipboard->system); + + EnterCriticalSection(&clipboard->lock); + if (clipboard->responseFile) + fclose(clipboard->responseFile); + LeaveCriticalSection(&clipboard->lock); + DeleteCriticalSection(&clipboard->lock); free(clipboard); } diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index aca7342..ac8e772 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -331,12 +331,15 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) break; case UWAC_EVENT_FRAME_DONE: + { + UwacReturnCode r; EnterCriticalSection(&context->critical); - rc = UwacWindowSubmitBuffer(context->window, false); + r = UwacWindowSubmitBuffer(context->window, false); LeaveCriticalSection(&context->critical); - if (rc != UWAC_SUCCESS) + if (r != UWAC_SUCCESS) return FALSE; - break; + } + break; case UWAC_EVENT_POINTER_ENTER: if (!wlf_handle_pointer_enter(instance, &event.mouse_enter_leave)) diff --git a/include/freerdp/locale/locale.h b/include/freerdp/locale/locale.h index 54ab2c6..6647bb2 100644 --- a/include/freerdp/locale/locale.h +++ b/include/freerdp/locale/locale.h @@ -62,6 +62,7 @@ #define BRETON 0x047E #define BULGARIAN 0x0402 #define CATALAN 0x0403 +#define CHEROKEE 0x045C #define CHINESE_TAIWAN 0x0404 #define CHINESE_PRC 0x0804 #define CHINESE_HONG_KONG 0x0C04 @@ -113,12 +114,14 @@ #define GREEK 0x0408 #define GREENLANDIC 0x046F #define GUJARATI 0x0447 +#define HAWAIIAN 0x0475 #define HEBREW 0x040D #define HINDI 0x0439 #define HUNGARIAN 0x040E #define ICELANDIC 0x040F #define IGBO 0x0470 #define INDONESIAN 0x0421 +#define INUKTITUT 0x045D #define IRISH 0x083C #define ITALIAN_STANDARD 0x0410 #define ITALIAN_SWISS 0x0810 @@ -146,6 +149,7 @@ #define MARATHI 0x044E #define MOHAWK 0x047C #define MONGOLIAN 0x0450 +#define MYANMAR 0x0455 #define NEPALI 0x0461 #define NORWEGIAN_BOKMAL 0x0414 #define NORWEGIAN_NYNORSK 0x0814 diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 26adb62..3b7a138 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -894,6 +894,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_TcpKeepAliveDelay (5192) #define FreeRDP_TcpKeepAliveInterval (5193) #define FreeRDP_TcpAckTimeout (5194) +#define FreeRDP_TcpConnectTimeout (5197) /** * FreeRDP Settings Data Structure @@ -1342,20 +1343,20 @@ struct rdp_settings /* Input Capabilities */ ALIGN64 char* KeyboardRemappingList; /* 2622 */ - ALIGN64 UINT32 KeyboardCodePage; /* 2623 */ - ALIGN64 UINT32 KeyboardLayout; /* 2624 */ - ALIGN64 UINT32 KeyboardType; /* 2625 */ - ALIGN64 UINT32 KeyboardSubType; /* 2626 */ - ALIGN64 UINT32 KeyboardFunctionKey; /* 2627 */ - ALIGN64 char* ImeFileName; /* 2628 */ - ALIGN64 BOOL UnicodeInput; /* 2629 */ - ALIGN64 BOOL FastPathInput; /* 2630 */ - ALIGN64 BOOL MultiTouchInput; /* 2631 */ - ALIGN64 BOOL MultiTouchGestures; /* 2632 */ - ALIGN64 UINT32 KeyboardHook; /* 2633 */ - ALIGN64 BOOL HasHorizontalWheel; /* 2634 */ - ALIGN64 BOOL HasExtendedMouseEvent; /* 2635 */ - UINT64 padding2688[2688 - 2636]; /* 2636 */ + ALIGN64 UINT32 KeyboardCodePage; /* 2623 */ + ALIGN64 UINT32 KeyboardLayout; /* 2624 */ + ALIGN64 UINT32 KeyboardType; /* 2625 */ + ALIGN64 UINT32 KeyboardSubType; /* 2626 */ + ALIGN64 UINT32 KeyboardFunctionKey; /* 2627 */ + ALIGN64 char* ImeFileName; /* 2628 */ + ALIGN64 BOOL UnicodeInput; /* 2629 */ + ALIGN64 BOOL FastPathInput; /* 2630 */ + ALIGN64 BOOL MultiTouchInput; /* 2631 */ + ALIGN64 BOOL MultiTouchGestures; /* 2632 */ + ALIGN64 UINT32 KeyboardHook; /* 2633 */ + ALIGN64 BOOL HasHorizontalWheel; /* 2634 */ + ALIGN64 BOOL HasExtendedMouseEvent; /* 2635 */ + UINT64 padding2688[2688 - 2636]; /* 2636 */ /* Brush Capabilities */ ALIGN64 UINT32 BrushSupportLevel; /* 2688 */ @@ -1545,7 +1546,9 @@ struct rdp_settings ALIGN64 UINT32 TcpKeepAliveDelay; /* 5192 */ ALIGN64 UINT32 TcpKeepAliveInterval; /* 5193 */ ALIGN64 UINT32 TcpAckTimeout; /* 5194 */ - UINT64 padding5312[5312 - 5195]; /* 5195 */ + UINT64 padding5197[5197 - 5195]; /* 5195 */ + ALIGN64 UINT32 TcpConnectTimeout; /* 5197 */ + UINT64 padding5312[5312 - 5198]; /* 5198 */ /** * WARNING: End of ABI stable zone! diff --git a/include/freerdp/update.h b/include/freerdp/update.h index d2797a2..71cb155 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -263,6 +263,7 @@ struct rdp_update * fills BITMAP_DATA struct members: flags, cbCompMainBodySize and cbCompFirstRowSize. */ BOOL autoCalculateBitmapData; + size_t offsetOrders; /* the offset to patch numberOrders in the stream */ }; #endif /* FREERDP_UPDATE_H */ diff --git a/libfreerdp/common/settings_getters.c b/libfreerdp/common/settings_getters.c index 2a34bb8..a3ce8e9 100644 --- a/libfreerdp/common/settings_getters.c +++ b/libfreerdp/common/settings_getters.c @@ -1570,6 +1570,9 @@ UINT32 freerdp_settings_get_uint32(const rdpSettings* settings, size_t id) case FreeRDP_TcpAckTimeout: return settings->TcpAckTimeout; + case FreeRDP_TcpConnectTimeout: + return settings->TcpConnectTimeout; + case FreeRDP_TcpKeepAliveDelay: return settings->TcpKeepAliveDelay; @@ -2021,6 +2024,10 @@ BOOL freerdp_settings_set_uint32(rdpSettings* settings, size_t id, UINT32 val) settings->TcpAckTimeout = val; break; + case FreeRDP_TcpConnectTimeout: + settings->TcpConnectTimeout = val; + break; + case FreeRDP_TcpKeepAliveDelay: settings->TcpKeepAliveDelay = val; break; diff --git a/libfreerdp/common/settings_str.c b/libfreerdp/common/settings_str.c index b7b8def..9a545f2 100644 --- a/libfreerdp/common/settings_str.c +++ b/libfreerdp/common/settings_str.c @@ -285,6 +285,7 @@ static const struct settings_str_entry settings_map[] = { { FreeRDP_StaticChannelCount, 3, "FreeRDP_StaticChannelCount" }, { FreeRDP_TargetNetAddressCount, 3, "FreeRDP_TargetNetAddressCount" }, { FreeRDP_TcpAckTimeout, 3, "FreeRDP_TcpAckTimeout" }, + { FreeRDP_TcpConnectTimeout, 3, "FreeRDP_TcpConnectTimeout" }, { FreeRDP_TcpKeepAliveDelay, 3, "FreeRDP_TcpKeepAliveDelay" }, { FreeRDP_TcpKeepAliveInterval, 3, "FreeRDP_TcpKeepAliveInterval" }, { FreeRDP_TcpKeepAliveRetries, 3, "FreeRDP_TcpKeepAliveRetries" }, diff --git a/libfreerdp/core/gateway/ncacn_http.c b/libfreerdp/core/gateway/ncacn_http.c index f288a0f..75da83d 100644 --- a/libfreerdp/core/gateway/ncacn_http.c +++ b/libfreerdp/core/gateway/ncacn_http.c @@ -105,7 +105,7 @@ BOOL rpc_ncacn_http_send_in_channel_request(RpcChannel* inChannel) BOOL rpc_ncacn_http_recv_in_channel_response(RpcChannel* inChannel, HttpResponse* response) { const char* token64 = NULL; - size_t ntlmTokenLength = 0; + int ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; rdpNtlm* ntlm; @@ -259,7 +259,7 @@ BOOL rpc_ncacn_http_send_out_channel_request(RpcChannel* outChannel, BOOL replac BOOL rpc_ncacn_http_recv_out_channel_response(RpcChannel* outChannel, HttpResponse* response) { const char* token64 = NULL; - size_t ntlmTokenLength = 0; + int ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; rdpNtlm* ntlm; diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index 72019ed..44de2c1 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -1190,7 +1190,7 @@ static BOOL rdg_handle_ntlm_challenge(rdpNtlm* ntlm, HttpResponse* response) BOOL continueNeeded = FALSE; size_t len; const char* token64 = NULL; - size_t ntlmTokenLength = 0; + int ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; long StatusCode; diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 3f8afae..f31b736 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -711,7 +711,9 @@ static BOOL rdp_write_info_packet(rdpRdp* rdp, wStream* s) if (!settings->RemoteAssistanceMode) { - if (settings->RedirectionPassword && settings->RedirectionPasswordLength > 0) + /* Ignore redirection password if we´re using smartcard and have the pin as password */ + if (((flags & INFO_PASSWORD_IS_SC_PIN) == 0) && settings->RedirectionPassword && + (settings->RedirectionPasswordLength > 0)) { union { BYTE* bp; diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 8357ff9..ac4e93f 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -277,6 +277,9 @@ static BOOL nego_tcp_connect(rdpNego* nego) { if (!nego->TcpConnected) { + const UINT32 TcpConnectTimeout = freerdp_settings_get_uint32( + nego->transport->context->settings, FreeRDP_TcpConnectTimeout); + if (nego->GatewayEnabled) { if (nego->GatewayBypassLocal) @@ -286,20 +289,21 @@ static BOOL nego_tcp_connect(rdpNego* nego) "Detecting if host can be reached locally. - This might take some time."); WLog_INFO(TAG, "To disable auto detection use /gateway-usage-method:direct"); transport_set_gateway_enabled(nego->transport, FALSE); - nego->TcpConnected = - transport_connect(nego->transport, nego->hostname, nego->port, 1); + nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, + TcpConnectTimeout); } if (!nego->TcpConnected) { transport_set_gateway_enabled(nego->transport, TRUE); - nego->TcpConnected = - transport_connect(nego->transport, nego->hostname, nego->port, 15); + nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, + TcpConnectTimeout); } } else { - nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, 15); + nego->TcpConnected = + transport_connect(nego->transport, nego->hostname, nego->port, TcpConnectTimeout); } } diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index eb425dd..d0c2b56 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -547,11 +547,13 @@ rdpSettings* freerdp_settings_new(DWORD flags) if (!settings->DynamicChannelArray) goto out_fail; - settings->TcpKeepAlive = TRUE; - settings->TcpKeepAliveRetries = 3; - settings->TcpKeepAliveDelay = 5; - settings->TcpKeepAliveInterval = 2; - settings->TcpAckTimeout = 9000; + if (!freerdp_settings_set_bool(settings, FreeRDP_TcpKeepAlive, TRUE) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveRetries, 3) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveDelay, 5) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveInterval, 2) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpAckTimeout, 9000) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpConnectTimeout, 15000)) + goto out_fail; if (!settings->ServerMode) { diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index ef5f7b1..60b4211 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -801,14 +801,14 @@ static BOOL freerdp_tcp_is_hostname_resolvable(rdpContext* context, const char* } static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct sockaddr* addr, - socklen_t addrlen, int timeout) + socklen_t addrlen, UINT32 timeout) { BOOL rc = FALSE; HANDLE handles[2]; int status = 0; int count = 0; u_long arg = 0; - DWORD tout = (timeout > 0) ? (DWORD)timeout * 1000U : INFINITE; + DWORD tout = (timeout > 0) ? timeout : INFINITE; handles[count] = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -894,7 +894,7 @@ static void peer_free(t_peer* peer) } static int freerdp_tcp_connect_multi(rdpContext* context, char** hostnames, UINT32* ports, - UINT32 count, int port, int timeout) + UINT32 count, UINT16 port, UINT32 timeout) { UINT32 index; UINT32 sindex = count; diff --git a/libfreerdp/core/test/settings_property_lists.h b/libfreerdp/core/test/settings_property_lists.h index ff35a7e..db8e5ed 100644 --- a/libfreerdp/core/test/settings_property_lists.h +++ b/libfreerdp/core/test/settings_property_lists.h @@ -282,6 +282,7 @@ static const size_t uint32_list_indices[] = { FreeRDP_StaticChannelCount, FreeRDP_TargetNetAddressCount, FreeRDP_TcpAckTimeout, + FreeRDP_TcpConnectTimeout, FreeRDP_TcpKeepAliveDelay, FreeRDP_TcpKeepAliveInterval, FreeRDP_TcpKeepAliveRetries, diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index e137c3d..448726e 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -931,6 +931,7 @@ static BOOL _update_begin_paint(rdpContext* context) return FALSE; Stream_SealLength(s); + Stream_GetLength(s, update->offsetOrders); Stream_Seek(s, 2); /* numberOrders (2 bytes) */ update->combineUpdates = TRUE; update->numberOrders = 0; @@ -941,16 +942,14 @@ static BOOL _update_begin_paint(rdpContext* context) static BOOL _update_end_paint(rdpContext* context) { wStream* s; - int headerLength; rdpUpdate* update = context->update; if (!update->us) return FALSE; s = update->us; - headerLength = Stream_Length(s); Stream_SealLength(s); - Stream_SetPosition(s, headerLength); + Stream_SetPosition(s, update->offsetOrders); Stream_Write_UINT16(s, update->numberOrders); /* numberOrders (2 bytes) */ Stream_SetPosition(s, Stream_Length(s)); @@ -962,6 +961,7 @@ static BOOL _update_end_paint(rdpContext* context) update->combineUpdates = FALSE; update->numberOrders = 0; + update->offsetOrders = 0; update->us = NULL; Stream_Free(s, TRUE); return TRUE; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index d72998a..fee8db5 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -323,7 +323,8 @@ static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) case BIO_CTRL_PUSH: if (next_bio && (next_bio != ssl_rbio)) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) SSL_set_bio(tls->ssl, next_bio, next_bio); CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO); #else @@ -347,7 +348,8 @@ static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) if (ssl_rbio != ssl_wbio) BIO_free_all(ssl_wbio); -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) if (next_bio) CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO); @@ -387,7 +389,8 @@ static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) BIO_push(ssl_rbio, next_bio); BIO_set_next(bio, ssl_rbio); -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) CRYPTO_add(&(ssl_rbio->references), 1, CRYPTO_LOCK_BIO); #else BIO_up_ref(ssl_rbio); diff --git a/libfreerdp/locale/CMakeLists.txt b/libfreerdp/locale/CMakeLists.txt index 1a300f2..9c74e20 100644 --- a/libfreerdp/locale/CMakeLists.txt +++ b/libfreerdp/locale/CMakeLists.txt @@ -38,10 +38,20 @@ set(${MODULE_PREFIX}_SUN_SRCS keyboard_sun.c keyboard_sun.h) +set(${MODULE_PREFIX}_APPLE_SRCS + keyboard_apple.c + keyboard_apple.h) + if(CMAKE_SYSTEM_NAME MATCHES Solaris) set(WITH_SUN true) endif() +if(APPLE AND (NOT IOS)) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_APPLE_SRCS}) + find_library(CARBON Carbon) + freerdp_library_add(${CARBON}) +endif() + if(WITH_X11) freerdp_definition_add(-DWITH_X11) freerdp_include_directory_add(${X11_INCLUDE_DIRS}) diff --git a/libfreerdp/locale/keyboard.c b/libfreerdp/locale/keyboard.c index eca0d63..4c5ae03 100644 --- a/libfreerdp/locale/keyboard.c +++ b/libfreerdp/locale/keyboard.c @@ -32,6 +32,10 @@ #include "liblocale.h" +#if defined(__MACOSX__) +#include "keyboard_apple.h" +#endif + #ifdef WITH_X11 #include "keyboard_x11.h" @@ -64,6 +68,11 @@ int freerdp_detect_keyboard(DWORD* keyboardLayoutId) *keyboardLayoutId = ((DWORD)GetKeyboardLayout(0) >> 16) & 0x0000FFFF; #endif +#if defined(__MACOSX__) + if (*keyboardLayoutId == 0) + freerdp_detect_keyboard_layout_from_cf(keyboardLayoutId); +#endif + #ifdef WITH_X11 if (*keyboardLayoutId == 0) freerdp_detect_keyboard_layout_from_xkb(keyboardLayoutId); @@ -148,7 +157,7 @@ DWORD freerdp_keyboard_init(DWORD keyboardLayoutId) for (keycode = 0; keycode < ARRAYSIZE(VIRTUAL_SCANCODE_TO_X11_KEYCODE); keycode++) { VIRTUAL_SCANCODE_TO_X11_KEYCODE - [RDP_SCANCODE_CODE(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode])] + [RDP_SCANCODE_CODE(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode])] [RDP_SCANCODE_EXTENDED(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode]) ? 1 : 0] = keycode; } diff --git a/libfreerdp/locale/keyboard_apple.c b/libfreerdp/locale/keyboard_apple.c new file mode 100644 index 0000000..d0d5921 --- /dev/null +++ b/libfreerdp/locale/keyboard_apple.c @@ -0,0 +1,244 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Apple Core Foundation Keyboard Mapping + * + * Copyright 2021 Thincast Technologies GmbH + * Copyright 2021 Martin Fleisz + * + * 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 "liblocale.h" + +#include +#include + +#include "keyboard_apple.h" + +struct KEYBOARD_LAYOUT_MAPPING_ +{ + const char* inputSourceId; /* Apple input source id (com.apple.keylayout or inputmethod) */ + DWORD code; /* mapped rdp keyboard layout id */ +}; +typedef struct KEYBOARD_LAYOUT_MAPPING_ KEYBOARD_LAYOUT_MAPPING; + +static const KEYBOARD_LAYOUT_MAPPING KEYBOARD_MAPPING_TABLE[] = { + { "com.apple.inputmethod.Kotoeri.Japanese", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Japanese.FullWidthRoman", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Japanese.HalfWidthKana", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Japanese.Katakana", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Katakana", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Roman", JAPANESE }, + { "com.apple.inputmethod.kotoeri.Ainu", JAPANESE }, + { "com.apple.keylayout.2SetHangul", KOREAN }, + { "com.apple.keylayout.390Hangul", KOREAN }, + { "com.apple.keylayout.3SetHangul", KOREAN }, + { "com.apple.keylayout.AfghanDari", DARI }, + { "com.apple.keylayout.AfghanPashto", PASHTO }, + { "com.apple.keylayout.AfghanUzbek", UZBEK_LATIN }, + { "com.apple.keylayout.Arabic", ARABIC_EGYPT }, + { "com.apple.keylayout.Arabic-QWERTY", ARABIC_EGYPT }, + { "com.apple.keylayout.ArabicPC", ARABIC_EGYPT }, + { "com.apple.keylayout.Armenian-HMQWERTY", ARMENIAN }, + { "com.apple.keylayout.Armenian-WesternQWERTY", ARMENIAN }, + { "com.apple.keylayout.Australian", ENGLISH_AUSTRALIAN }, + { "com.apple.keylayout.Austrian", GERMAN_AUSTRIAN }, + { "com.apple.keylayout.Azeri", AZERI_LATIN }, + { "com.apple.keylayout.Bangla", BENGALI_INDIA }, + { "com.apple.keylayout.Bangla-QWERTY", BENGALI_INDIA }, + { "com.apple.keylayout.Belgian", DUTCH_BELGIAN }, + { "com.apple.keylayout.Brazilian", PORTUGUESE_BRAZILIAN }, + { "com.apple.keylayout.British", ENGLISH_UNITED_KINGDOM }, + { "com.apple.keylayout.British-PC", ENGLISH_UNITED_KINGDOM }, + { "com.apple.keylayout.Bulgarian", BULGARIAN }, + { "com.apple.keylayout.Bulgarian-Phonetic", BULGARIAN }, + { "com.apple.keylayout.Byelorussian", BELARUSIAN }, + { "com.apple.keylayout.Canadian", ENGLISH_CANADIAN }, + { "com.apple.keylayout.Canadian-CSA", FRENCH_CANADIAN }, + { "com.apple.keylayout.CangjieKeyboard", CHINESE_TAIWAN }, + { "com.apple.keylayout.Cherokee-Nation", CHEROKEE }, + { "com.apple.keylayout.Cherokee-QWERTY", CHEROKEE }, + { "com.apple.keylayout.Colemak", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Croatian", CROATIAN }, + { "com.apple.keylayout.Croatian-PC", CROATIAN }, + { "com.apple.keylayout.Czech", CZECH }, + { "com.apple.keylayout.Czech-QWERTY", CZECH }, + { "com.apple.keylayout.DVORAK-QWERTYCMD", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Danish", DANISH }, + { "com.apple.keylayout.Devanagari", HINDI }, + { "com.apple.keylayout.Devanagari-QWERTY", HINDI }, + { "com.apple.keylayout.Dutch", DUTCH_STANDARD }, + { "com.apple.keylayout.Dvorak", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Dvorak-Left", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Dvorak-Right", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Estonian", ESTONIAN }, + { "com.apple.keylayout.Faroese", FAEROESE }, + { "com.apple.keylayout.Finnish", FINNISH }, + { "com.apple.keylayout.FinnishExtended", FINNISH }, + { "com.apple.keylayout.FinnishSami-PC", FINNISH }, + { "com.apple.keylayout.French", FRENCH_STANDARD }, + { "com.apple.keylayout.French-PC", FRENCH_STANDARD }, + { "com.apple.keylayout.French-numerical", FRENCH_STANDARD }, + { "com.apple.keylayout.GJCRomaja", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Georgian-QWERTY", GEORGIAN }, + { "com.apple.keylayout.German", GERMAN_STANDARD }, + { "com.apple.keylayout.Greek", GREEK }, + { "com.apple.keylayout.GreekPolytonic", GREEK }, + { "com.apple.keylayout.Gujarati", GUJARATI }, + { "com.apple.keylayout.Gujarati-QWERTY", GUJARATI }, + { "com.apple.keylayout.Gurmukhi", PUNJABI }, + { "com.apple.keylayout.Gurmukhi-QWERTY", PUNJABI }, + { "com.apple.keylayout.HNCRomaja", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Hawaiian", HAWAIIAN }, + { "com.apple.keylayout.Hebrew", HEBREW }, + { "com.apple.keylayout.Hebrew-PC", HEBREW }, + { "com.apple.keylayout.Hebrew-QWERTY", HEBREW }, + { "com.apple.keylayout.Hungarian", HUNGARIAN }, + { "com.apple.keylayout.Hungarian-QWERTY", HUNGARIAN }, + { "com.apple.keylayout.Icelandic", ICELANDIC }, + { "com.apple.keylayout.Inuktitut-Nunavut", INUKTITUT }, + { "com.apple.keylayout.Inuktitut-Nutaaq", INUKTITUT }, + { "com.apple.keylayout.Inuktitut-QWERTY", INUKTITUT }, + { "com.apple.keylayout.InuttitutNunavik", INUKTITUT }, + { "com.apple.keylayout.Irish", ENGLISH_IRELAND }, + { "com.apple.keylayout.IrishExtended", IRISH }, + { "com.apple.keylayout.Italian", ITALIAN_STANDARD }, + { "com.apple.keylayout.Italian-Pro", ITALIAN_STANDARD }, + { "com.apple.keylayout.Jawi-QWERTY", ARABIC_SAUDI_ARABIA }, + { "com.apple.keylayout.Kannada", KANNADA }, + { "com.apple.keylayout.Kannada-QWERTY", KANNADA }, + { "com.apple.keylayout.Kazakh", KAZAKH }, + { "com.apple.keylayout.Khmer", KHMER }, + { "com.apple.keylayout.Latvian", LATVIAN }, + { "com.apple.keylayout.Lithuanian", LITHUANIAN }, + { "com.apple.keylayout.Macedonian", MACEDONIAN }, + { "com.apple.keylayout.Malayalam", MALAYALAM }, + { "com.apple.keylayout.Malayalam-QWERTY", MALAYALAM }, + { "com.apple.keylayout.Maltese", MALTESE }, + { "com.apple.keylayout.Maori", MAORI }, + { "com.apple.keylayout.Myanmar-QWERTY", MYANMAR }, + { "com.apple.keylayout.Nepali", NEPALI }, + { "com.apple.keylayout.NorthernSami", SAMI_NORTHERN_NORWAY }, + { "com.apple.keylayout.Norwegian", NORWEGIAN_BOKMAL }, + { "com.apple.keylayout.NorwegianExtended", NORWEGIAN_BOKMAL }, + { "com.apple.keylayout.NorwegianSami-PC", NORWEGIAN_BOKMAL }, + { "com.apple.keylayout.Oriya", ORIYA }, + { "com.apple.keylayout.Persian", FARSI }, + { "com.apple.keylayout.Persian-ISIRI2901", FARSI }, + { "com.apple.keylayout.Polish", POLISH }, + { "com.apple.keylayout.PolishPro", POLISH }, + { "com.apple.keylayout.Portuguese", PORTUGUESE_STANDARD }, + { "com.apple.keylayout.Romanian", ROMANIAN }, + { "com.apple.keylayout.Romanian-Standard", ROMANIAN }, + { "com.apple.keylayout.Russian", RUSSIAN }, + { "com.apple.keylayout.Russian-Phonetic", RUSSIAN }, + { "com.apple.keylayout.RussianWin", RUSSIAN }, + { "com.apple.keylayout.Sami-PC", SAMI_NORTHERN_SWEDEN }, + { "com.apple.keylayout.Serbian", SERBIAN_CYRILLIC_BOSNIA_HERZEGOVINA }, + { "com.apple.keylayout.Serbian-Latin", SERBIAN_LATIN_BOSNIA_HERZEGOVINA }, + { "com.apple.keylayout.Sinhala", SINHALA }, + { "com.apple.keylayout.Sinhala-QWERTY", SINHALA }, + { "com.apple.keylayout.Slovak", SLOVAK }, + { "com.apple.keylayout.Slovak-QWERTY", SLOVAK }, + { "com.apple.keylayout.Slovenian", SLOVENIAN }, + { "com.apple.keylayout.Spanish", SPANISH_TRADITIONAL_SORT }, + { "com.apple.keylayout.Spanish-ISO", SPANISH_MODERN_SORT }, + { "com.apple.keylayout.Swedish", SWEDISH }, + { "com.apple.keylayout.Swedish-Pro", SWEDISH }, + { "com.apple.keylayout.SwedishSami-PC", SWEDISH }, + { "com.apple.keylayout.SwissFrench", FRENCH_SWISS }, + { "com.apple.keylayout.SwissGerman", GERMAN_SWISS }, + { "com.apple.keylayout.Telugu", TELUGU }, + { "com.apple.keylayout.Telugu-QWERTY", TELUGU }, + { "com.apple.keylayout.Thai", THAI }, + { "com.apple.keylayout.Thai-PattaChote", THAI }, + { "com.apple.keylayout.Tibetan-QWERTY", TIBETAN_PRC }, + { "com.apple.keylayout.Tibetan-Wylie", TIBETAN_PRC }, + { "com.apple.keylayout.TibetanOtaniUS", TIBETAN_PRC }, + { "com.apple.keylayout.Turkish", TURKISH }, + { "com.apple.keylayout.Turkish-QWERTY", TURKISH }, + { "com.apple.keylayout.Turkish-QWERTY-PC", TURKISH }, + { "com.apple.keylayout.US", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.USExtended", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.USInternational-PC", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Ukrainian", UKRAINIAN }, + { "com.apple.keylayout.Ukrainian-PC", UKRAINIAN }, + { "com.apple.keylayout.UnicodeHexInput", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Urdu", URDU }, + { "com.apple.keylayout.Uyghur", UIGHUR }, + { "com.apple.keylayout.Vietnamese", VIETNAMESE }, + { "com.apple.keylayout.Welsh", WELSH } +}; + +int freerdp_detect_keyboard_layout_from_cf(DWORD* keyboardLayoutId) +{ + int i; + CFIndex length; + char* inputSourceId = NULL; + CFStringRef inputSourceIdRef; + TISInputSourceRef inputSrc = TISCopyCurrentKeyboardLayoutInputSource(); + if (!inputSrc) + { + DEBUG_KBD("Failed to get current keyboard layout input source!"); + return 0; + } + + /* get current input source id */ + inputSourceIdRef = (CFStringRef)TISGetInputSourceProperty(inputSrc, kTISPropertyInputSourceID); + if (!inputSourceIdRef) + { + DEBUG_KBD("Failed to get input source id!"); + goto done; + } + + /* convert it to a C-string */ + length = CFStringGetLength(inputSourceIdRef); + length = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; + inputSourceId = (char*)malloc(length); + if (!inputSourceId) + { + DEBUG_KBD("Failed to allocate string buffer!"); + goto done; + } + + if (!CFStringGetCString(inputSourceIdRef, inputSourceId, length, kCFStringEncodingUTF8)) + { + DEBUG_KBD("Failed to convert CFString to C-string!"); + goto done; + } + + /* Search for the id in the mapping table */ + for (i = 0; i < ARRAYSIZE(KEYBOARD_MAPPING_TABLE); ++i) + { + if (strcmp(inputSourceId, KEYBOARD_MAPPING_TABLE[i].inputSourceId) == 0) + { + *keyboardLayoutId = KEYBOARD_MAPPING_TABLE[i].code; + break; + } + } + +done: + free(inputSourceId); + CFRelease(inputSrc); + if (*keyboardLayoutId > 0) + return *keyboardLayoutId; + + return 0; +} diff --git a/libfreerdp/locale/keyboard_apple.h b/libfreerdp/locale/keyboard_apple.h new file mode 100644 index 0000000..cd3c3e7 --- /dev/null +++ b/libfreerdp/locale/keyboard_apple.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Apple Core Foundation Keyboard Mapping + * + * Copyright 2021 Thincast Technologies GmbH + * Copyright 2021 Martin Fleisz + * + * 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_LOCALE_KEYBOARD_APPLE_H +#define FREERDP_LOCALE_KEYBOARD_APPLE_H + +#include + +FREERDP_LOCAL int freerdp_detect_keyboard_layout_from_cf(DWORD* keyboardLayoutId); + +#endif /* FREERDP_LOCALE_KEYBOARD_APPLE_H */ diff --git a/libfreerdp/locale/locale.c b/libfreerdp/locale/locale.c index 97ae9e4..e7c6d00 100644 --- a/libfreerdp/locale/locale.c +++ b/libfreerdp/locale/locale.c @@ -3,6 +3,8 @@ * Microsoft Locales * * Copyright 2009-2012 Marc-Andre Moreau + * Copyright 2021 Thincast Technologies GmbH + * Copyright 2021 Martin Fleisz * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,22 +23,32 @@ #include "config.h" #endif +#if defined(__APPLE__) +#include +#include +#endif + #include #include #include #include +#include #include #include "liblocale.h" #include +#define LOCALE_LANGUAGE_LEN 6 +#define LOCALE_COUNTRY_LEN 10 + struct _SYSTEM_LOCALE { - char language[4]; /* Two or three letter language code */ - char country[10]; /* Two or three letter country code (Sometimes with Cyrl_ prefix) */ - DWORD code; /* 32-bit unsigned integer corresponding to the locale */ + char language[LOCALE_LANGUAGE_LEN]; /* Two or three letter language code */ + char country[LOCALE_COUNTRY_LEN]; /* Two or three letter country code (Sometimes with Cyrl_ + prefix) */ + DWORD code; /* 32-bit unsigned integer corresponding to the locale */ }; typedef struct _SYSTEM_LOCALE SYSTEM_LOCALE; @@ -642,77 +654,118 @@ static const LOCALE_KEYBOARD_LAYOUTS LOCALE_KEYBOARD_LAYOUTS_TABLE[] = { { XHOSA, { 0x00000409, 0x00000409, 0x0, 0x0, 0x0 } }, }; -static BOOL freerdp_get_system_language_and_country_codes(char* language, char* country) +static BOOL freerdp_get_system_language_and_country_codes(char* language, size_t languageLen, + char* country, size_t countryLen) { - int dot; - DWORD nSize; - int underscore; - char* env_lang = NULL; - LPCSTR lang = "LANG"; - /* LANG = _. */ - nSize = GetEnvironmentVariableA(lang, NULL, 0); + assert(language); + assert(languageLen > 0); + assert(country); + assert(countryLen); - if (!nSize) - return FALSE; /* LANG environment variable was not set */ - - env_lang = (char*)malloc(nSize); - - if (!env_lang) - return FALSE; - - if (GetEnvironmentVariableA(lang, env_lang, nSize) != - nSize - 1) /* Get locale from environment variable LANG */ +#if defined(__APPLE__) { + CFIndex strSize; + CFStringRef langRef, countryRef; + CFLocaleRef localeRef = CFLocaleCopyCurrent(); + if (!localeRef) + return FALSE; + + langRef = (CFStringRef)CFLocaleGetValue(localeRef, kCFLocaleLanguageCode); + countryRef = (CFStringRef)CFLocaleGetValue(localeRef, kCFLocaleCountryCode); + if (!langRef || !countryRef) + { + CFRelease(localeRef); + return FALSE; + } + + if (!CFStringGetCString(langRef, language, languageLen, kCFStringEncodingUTF8) || + !CFStringGetCString(countryRef, country, countryLen, kCFStringEncodingUTF8)) + { + CFRelease(localeRef); + return FALSE; + } + + CFRelease(localeRef); + return TRUE; + } +#else + { + int dot; + DWORD nSize; + int underscore; + char* env_lang = NULL; + LPCSTR lang = "LANG"; + /* LANG = _. */ + nSize = GetEnvironmentVariableA(lang, NULL, 0); + + if (!nSize) + return FALSE; /* LANG environment variable was not set */ + + env_lang = (char*)malloc(nSize); + + if (!env_lang) + return FALSE; + + if (GetEnvironmentVariableA(lang, env_lang, nSize) != + nSize - 1) /* Get locale from environment variable LANG */ + { + free(env_lang); + return FALSE; + } + + underscore = strcspn(env_lang, "_"); + + if (underscore > 3) + { + free(env_lang); + return FALSE; /* The language name should not be more than 3 letters long */ + } + else + { + /* Get language code */ + size_t len = MIN(languageLen - 1, underscore); + strncpy(language, env_lang, len); + language[len] = '\0'; + } + + dot = strcspn(env_lang, "."); + + /* Get country code */ + if (dot > underscore) + { + size_t len = MIN(countryLen - 1, dot - underscore - 1); + strncpy(country, &env_lang[underscore + 1], len); + country[len] = '\0'; + } + else + { + free(env_lang); + return FALSE; /* Invalid locale */ + } + free(env_lang); - return FALSE; + return TRUE; } - - underscore = strcspn(env_lang, "_"); - - if (underscore > 3) - { - free(env_lang); - return FALSE; /* The language name should not be more than 3 letters long */ - } - else - { - /* Get language code */ - strncpy(language, env_lang, underscore); - language[underscore] = '\0'; - } - - dot = strcspn(env_lang, "."); - - /* Get country code */ - if (dot > underscore) - { - strncpy(country, &env_lang[underscore + 1], dot - underscore - 1); - country[dot - underscore - 1] = '\0'; - } - else - { - free(env_lang); - return FALSE; /* Invalid locale */ - } - - free(env_lang); - return TRUE; +#endif } -static SYSTEM_LOCALE* freerdp_detect_system_locale(void) +static const SYSTEM_LOCALE* freerdp_detect_system_locale(void) { size_t i; - char language[4]; - char country[10]; - SYSTEM_LOCALE* locale = NULL; - freerdp_get_system_language_and_country_codes(language, country); + char language[LOCALE_LANGUAGE_LEN] = { 0 }; + char country[LOCALE_COUNTRY_LEN] = { 0 }; + const SYSTEM_LOCALE* locale = NULL; + + freerdp_get_system_language_and_country_codes(language, ARRAYSIZE(language), country, + ARRAYSIZE(country)); for (i = 0; i < ARRAYSIZE(SYSTEM_LOCALE_TABLE); i++) { - if ((strcmp(language, SYSTEM_LOCALE_TABLE[i].language) == 0) && - (strcmp(country, SYSTEM_LOCALE_TABLE[i].country) == 0)) + const SYSTEM_LOCALE* current = &SYSTEM_LOCALE_TABLE[i]; + + if ((strcmp(language, current->language) == 0) && (strcmp(country, current->country) == 0)) { - locale = (SYSTEM_LOCALE*)&SYSTEM_LOCALE_TABLE[i]; + locale = current; break; } } @@ -722,7 +775,7 @@ static SYSTEM_LOCALE* freerdp_detect_system_locale(void) DWORD freerdp_get_system_locale_id(void) { - SYSTEM_LOCALE* locale; + const SYSTEM_LOCALE* locale; locale = freerdp_detect_system_locale(); if (locale != NULL) @@ -737,8 +790,10 @@ const char* freerdp_get_system_locale_name_from_id(DWORD localeId) for (index = 0; index < ARRAYSIZE(LOCALE_NAME_TABLE); index++) { - if (localeId == LOCALE_NAME_TABLE[index].localeId) - return LOCALE_NAME_TABLE[index].name; + const LOCALE_NAME* const current = &LOCALE_NAME_TABLE[index]; + + if (localeId == current->localeId) + return current->name; } return NULL; @@ -747,10 +802,12 @@ const char* freerdp_get_system_locale_name_from_id(DWORD localeId) int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId) { size_t i, j; - char language[4]; - char country[10]; - SYSTEM_LOCALE* locale; - freerdp_get_system_language_and_country_codes(language, country); + char language[LOCALE_LANGUAGE_LEN] = { 0 }; + char country[LOCALE_COUNTRY_LEN] = { 0 }; + const SYSTEM_LOCALE* locale; + + freerdp_get_system_language_and_country_codes(language, ARRAYSIZE(language), country, + ARRAYSIZE(country)); if ((strcmp(language, "C") == 0) || (strcmp(language, "POSIX") == 0)) { @@ -767,22 +824,24 @@ int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId) for (i = 0; i < ARRAYSIZE(LOCALE_KEYBOARD_LAYOUTS_TABLE); i++) { - if (LOCALE_KEYBOARD_LAYOUTS_TABLE[i].locale == locale->code) + const LOCALE_KEYBOARD_LAYOUTS* const current = &LOCALE_KEYBOARD_LAYOUTS_TABLE[i]; + + if (current->locale == locale->code) { /* Locale found in list of default keyboard layouts */ for (j = 0; j < 5; j++) { - if (LOCALE_KEYBOARD_LAYOUTS_TABLE[i].keyboardLayouts[j] == ENGLISH_UNITED_STATES) + if (current->keyboardLayouts[j] == ENGLISH_UNITED_STATES) { continue; /* Skip, try to get a more localized keyboard layout */ } - else if (LOCALE_KEYBOARD_LAYOUTS_TABLE[i].keyboardLayouts[j] == 0) + else if (current->keyboardLayouts[j] == 0) { break; /* No more keyboard layouts */ } else { - *keyboardLayoutId = LOCALE_KEYBOARD_LAYOUTS_TABLE[i].keyboardLayouts[j]; + *keyboardLayoutId = current->keyboardLayouts[j]; return 0; } } diff --git a/libfreerdp/utils/signal.c b/libfreerdp/utils/signal.c index 0510ef4..b529b78 100644 --- a/libfreerdp/utils/signal.c +++ b/libfreerdp/utils/signal.c @@ -43,6 +43,7 @@ int freerdp_handle_signals(void) #else #include +#include volatile sig_atomic_t terminal_needs_reset = 0; int terminal_fildes = 0; @@ -53,8 +54,15 @@ static void fatal_handler(int signum) { struct sigaction default_sigaction; sigset_t this_mask; - WLog_INFO(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum); + static BOOL recursive = FALSE; + if (!recursive) + { + recursive = TRUE; + WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum); + + winpr_log_backtrace(TAG, WLOG_ERROR, 20); + } if (terminal_needs_reset) tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags); diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 036b50f..620f9a7 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -51,7 +51,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.4.1") +set(RAW_VERSION_STRING "2.5.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/winpr/libwinpr/crypto/cipher.c b/winpr/libwinpr/crypto/cipher.c index e2477f3..41725ab 100644 --- a/winpr/libwinpr/crypto/cipher.c +++ b/winpr/libwinpr/crypto/cipher.c @@ -29,9 +29,6 @@ #include #include #include -#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) -#include -#endif #endif #ifdef WITH_MBEDTLS @@ -61,11 +58,6 @@ static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOO if (keylen > INT_MAX) return NULL; -#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) - if (OSSL_PROVIDER_load(NULL, "legacy") == NULL) - return NULL; -#endif - if (!(ctx = (WINPR_RC4_CTX*)EVP_CIPHER_CTX_new())) return NULL; diff --git a/winpr/libwinpr/registry/registry.c b/winpr/libwinpr/registry/registry.c index 726233e..e0c148b 100644 --- a/winpr/libwinpr/registry/registry.c +++ b/winpr/libwinpr/registry/registry.c @@ -34,18 +34,18 @@ #include #include #include + #include +#include #include "registry_reg.h" static Reg* instance = NULL; -static Reg* RegGetInstance() +static Reg* RegGetInstance(void) { if (!instance) - { instance = reg_open(1); - } return instance; } @@ -213,18 +213,23 @@ LONG RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesir LONG RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { - Reg* reg; RegKey* pKey; - reg = RegGetInstance(); + Reg* reg = RegGetInstance(); if (!reg) return -1; + if (hKey != HKEY_LOCAL_MACHINE) + return ERROR_FILE_NOT_FOUND; + + assert(reg->root_key); pKey = reg->root_key->subkeys; while (pKey != NULL) { - if (_stricmp(pKey->subname, lpSubKey) == 0) + assert(lpSubKey); + + if (pKey->subname && (_stricmp(pKey->subname, lpSubKey) == 0)) { *phkResult = (HKEY)pKey; return ERROR_SUCCESS; @@ -271,24 +276,48 @@ LONG RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD RegKey* key; RegVal* pValue; + WINPR_UNUSED(lpReserved); + key = (RegKey*)hKey; + assert(key); + pValue = key->values; while (pValue != NULL) { if (strcmp(pValue->name, lpValueName) == 0) { + if (lpType) + *lpType = pValue->type; + if (pValue->type == REG_DWORD) { DWORD* pData = (DWORD*)lpData; - if (pData != NULL) + if (lpcbData) { - *pData = pValue->data.dword; + DWORD size = *lpcbData; + *lpcbData = sizeof(DWORD); + if (pData) + { + if (size < *lpcbData) + return ERROR_MORE_DATA; + } } - *lpcbData = sizeof(DWORD); + if (pData != NULL) + { + DWORD size; + assert(lpcbData); + size = *lpcbData; + *lpcbData = sizeof(DWORD); + if (size < sizeof(DWORD)) + return ERROR_MORE_DATA; + *pData = pValue->data.dword; + } + else if (lpcbData != NULL) + *lpcbData = sizeof(DWORD); return ERROR_SUCCESS; } else if (pValue->type == REG_SZ) @@ -300,11 +329,18 @@ LONG RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD if (pData != NULL) { + DWORD size; + assert(lpcbData); + + size = *lpcbData; + *lpcbData = length; + if (size < length) + return ERROR_MORE_DATA; memcpy(pData, pValue->data.string, length); pData[length] = '\0'; } - - *lpcbData = (UINT32)length; + else if (lpcbData) + *lpcbData = (UINT32)length; return ERROR_SUCCESS; } diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index 353e490..511d927 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -35,12 +36,14 @@ #include "../log.h" #define TAG WINPR_TAG("registry") +#define WINPR_ASSERT assert + #define WINPR_HKLM_HIVE "/etc/winpr/HKLM.reg" struct reg_data_type { char* tag; - int length; + size_t length; DWORD type; }; @@ -52,50 +55,71 @@ static struct reg_data_type REG_DATA_TYPE_TABLE[] = { { "\"", 1, REG_SZ }, { "hex:", 4, REG_BINARY }, { "hex(2):\"", 8, REG_EXPAND_SZ }, { "hex(7):\"", 8, REG_MULTI_SZ }, - { "hex(b):\"", 8, REG_QWORD }, - { NULL, 0, 0 } }; + { "hex(b):\"", 8, REG_QWORD } }; -static char* REG_DATA_TYPE_STRINGS[] = { "REG_NONE", - "REG_SZ", - "REG_EXPAND_SZ", - "REG_BINARY", - "REG_DWORD", - "REG_DWORD_BIG_ENDIAN", - "REG_LINK", - "REG_MULTI_SZ", - "REG_RESOURCE_LIST", - "REG_FULL_RESOURCE_DESCRIPTOR", - "REG_RESOURCE_REQUIREMENTS_LIST", - "REG_QWORD" }; - -static void reg_load_start(Reg* reg) +static char* reg_data_type_string(DWORD type) { + switch (type) + { + case REG_NONE: + return "REG_NONE"; + case REG_SZ: + return "REG_SZ"; + case REG_EXPAND_SZ: + return "REG_EXPAND_SZ"; + case REG_BINARY: + return "REG_BINARY"; + case REG_DWORD: + return "REG_DWORD"; + case REG_DWORD_BIG_ENDIAN: + return "REG_DWORD_BIG_ENDIAN"; + case REG_LINK: + return "REG_LINK"; + case REG_MULTI_SZ: + return "REG_MULTI_SZ"; + case REG_RESOURCE_LIST: + return "REG_RESOURCE_LIST"; + case REG_FULL_RESOURCE_DESCRIPTOR: + return "REG_FULL_RESOURCE_DESCRIPTOR"; + case REG_RESOURCE_REQUIREMENTS_LIST: + return "REG_RESOURCE_REQUIREMENTS_LIST"; + case REG_QWORD: + return "REG_QWORD"; + default: + return "REG_UNKNOWN"; + } +} + +static BOOL reg_load_start(Reg* reg) +{ + char* buffer; INT64 file_size; + + WINPR_ASSERT(reg); + WINPR_ASSERT(reg->fp); + _fseeki64(reg->fp, 0, SEEK_END); file_size = _ftelli64(reg->fp); _fseeki64(reg->fp, 0, SEEK_SET); reg->line = NULL; reg->next_line = NULL; - reg->buffer = NULL; if (file_size < 1) - return; + return FALSE; - reg->buffer = (char*)malloc(file_size + 2); + buffer = (char*)realloc(reg->buffer, (size_t)file_size + 2); - if (!reg->buffer) - return; + if (!buffer) + return FALSE; + reg->buffer = buffer; - if (fread(reg->buffer, file_size, 1, reg->fp) != 1) - { - free(reg->buffer); - reg->buffer = NULL; - return; - } + if (fread(reg->buffer, (size_t)file_size, 1, reg->fp) != 1) + return FALSE; reg->buffer[file_size] = '\n'; reg->buffer[file_size + 1] = '\0'; reg->next_line = strtok(reg->buffer, "\n"); + return TRUE; } static void reg_load_finish(Reg* reg) @@ -112,15 +136,23 @@ static void reg_load_finish(Reg* reg) static RegVal* reg_load_value(Reg* reg, RegKey* key) { - int index; - char* p[5]; - int length; - char* name; + size_t index; + char* p[5] = { 0 }; + size_t length; + char* name = NULL; char* type; char* data; - RegVal* value; + RegVal* value = NULL; + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + WINPR_ASSERT(reg->line); + p[0] = reg->line + 1; p[1] = strstr(p[0], "\"="); + if (!p[1]) + return NULL; + p[2] = p[1] + 2; type = p[2]; @@ -129,67 +161,85 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) else p[3] = strchr(p[2], ':'); + if (!p[3]) + return NULL; + data = p[3] + 1; - length = p[1] - p[0]; - name = (char*)malloc(length + 1); + length = (size_t)(p[1] - p[0]); + if (length < 1) + goto fail; + + name = (char*)calloc(length + 1, sizeof(char)); if (!name) - return NULL; + goto fail; memcpy(name, p[0], length); - name[length] = '\0'; - value = (RegVal*)malloc(sizeof(RegVal)); + value = (RegVal*)calloc(1, sizeof(RegVal)); if (!value) - { - free(name); - return NULL; - } + goto fail; value->name = name; value->type = REG_NONE; - value->next = value->prev = NULL; - for (index = 0; REG_DATA_TYPE_TABLE[index].length > 0; index++) + for (index = 0; index < ARRAYSIZE(REG_DATA_TYPE_TABLE); index++) { - if (strncmp(type, REG_DATA_TYPE_TABLE[index].tag, REG_DATA_TYPE_TABLE[index].length) == 0) + const struct reg_data_type* current = ®_DATA_TYPE_TABLE[index]; + WINPR_ASSERT(current->tag); + WINPR_ASSERT(current->length > 0); + WINPR_ASSERT(current->type != REG_NONE); + + if (strncmp(type, current->tag, current->length) == 0) { - value->type = REG_DATA_TYPE_TABLE[index].type; + value->type = current->type; break; } } - if (value->type == REG_DWORD) + switch (value->type) { - unsigned long val; - errno = 0; - val = strtoul(data, NULL, 16); - - if ((errno != 0) || (val > UINT32_MAX)) + case REG_DWORD: { - free(value); - free(name); - return NULL; + unsigned long val; + errno = 0; + val = strtoul(data, NULL, 16); + + if ((errno != 0) || (val > UINT32_MAX)) + goto fail; + + value->data.dword = (DWORD)val; } - - value->data.dword = val; - } - else if (value->type == REG_SZ) - { - p[4] = strchr(data, '"'); - p[4][0] = '\0'; - value->data.string = _strdup(data); - - if (!value->data.string) + break; + case REG_SZ: { - free(value); - free(name); - return NULL; + size_t len, cmp; + char* end; + char* start = strchr(data, '"'); + if (!start) + goto fail; + + /* Check for terminating quote, check it is the last symbol */ + len = strlen(start); + end = strchr(start + 1, '"'); + if (!end) + goto fail; + cmp = end - start + 1; + if (len != cmp) + goto fail; + if (start[0] == '"') + start++; + if (end[0] == '"') + end[0] = '\0'; + value->data.string = _strdup(start); + + if (!value->data.string) + goto fail; } - } - else - { - WLog_ERR(TAG, "unimplemented format: %s", REG_DATA_TYPE_STRINGS[value->type]); + break; + default: + WLog_ERR(TAG, "unimplemented format: %s", reg_data_type_string(value->type)); + break; } if (!key->values) @@ -210,6 +260,11 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) } return value; + +fail: + free(value); + free(name); + return NULL; } static BOOL reg_load_has_next_line(Reg* reg) @@ -233,15 +288,21 @@ static char* reg_load_get_next_line(Reg* reg) static char* reg_load_peek_next_line(Reg* reg) { + WINPR_ASSERT(reg); return reg->next_line; } static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) { - char* name; - char* path; - char* save; - int length; + char* name = NULL; + char* path = NULL; + char* save = NULL; + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + WINPR_ASSERT(subkey); + WINPR_ASSERT(subkey->name); + path = _strdup(subkey->name); if (!path) @@ -253,9 +314,8 @@ static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) { if (strcmp(key->name, name) == 0) { - length = strlen(name); - name += length + 1; - subkey->subname = _strdup(name); + if (save) + subkey->subname = _strdup(save); /* TODO: free allocated memory in error case */ if (!subkey->subname) @@ -274,19 +334,24 @@ static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) static RegKey* reg_load_key(Reg* reg, RegKey* key) { char* p[2]; - int length; - char* line; + size_t length; RegKey* subkey; + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + + WINPR_ASSERT(reg->line); p[0] = reg->line + 1; p[1] = strrchr(p[0], ']'); - subkey = (RegKey*)malloc(sizeof(RegKey)); + if (!p[1]) + return NULL; + + subkey = (RegKey*)calloc(1, sizeof(RegKey)); if (!subkey) return NULL; - subkey->values = NULL; - subkey->prev = subkey->next = NULL; - length = p[1] - p[0]; + length = (size_t)(p[1] - p[0]); subkey->name = (char*)malloc(length + 1); if (!subkey->name) @@ -300,7 +365,7 @@ static RegKey* reg_load_key(Reg* reg, RegKey* key) while (reg_load_has_next_line(reg)) { - line = reg_load_peek_next_line(reg); + char* line = reg_load_peek_next_line(reg); if (line[0] == '[') break; @@ -354,16 +419,16 @@ static void reg_load(Reg* reg) static void reg_unload_value(Reg* reg, RegVal* value) { - if (value->type == REG_DWORD) + WINPR_ASSERT(reg); + WINPR_ASSERT(value); + + switch (value->type) { - } - else if (value->type == REG_SZ) - { - free(value->data.string); - } - else - { - WLog_ERR(TAG, "unimplemented format: %s", REG_DATA_TYPE_STRINGS[value->type]); + case REG_SZ: + free(value->data.string); + break; + default: + break; } free(value); @@ -372,12 +437,15 @@ static void reg_unload_value(Reg* reg, RegVal* value) static void reg_unload_key(Reg* reg, RegKey* key) { RegVal* pValue; - RegVal* pValueNext; + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + pValue = key->values; while (pValue != NULL) { - pValueNext = pValue->next; + RegVal* pValueNext = pValue->next; reg_unload_value(reg, pValue); pValue = pValueNext; } @@ -389,23 +457,26 @@ static void reg_unload_key(Reg* reg, RegKey* key) static void reg_unload(Reg* reg) { RegKey* pKey; - RegKey* pKeyNext; - pKey = reg->root_key->subkeys; - while (pKey != NULL) + WINPR_ASSERT(reg); + if (reg->root_key) { - pKeyNext = pKey->next; - reg_unload_key(reg, pKey); - pKey = pKeyNext; - } + pKey = reg->root_key->subkeys; - free(reg->root_key); + while (pKey != NULL) + { + RegKey* pKeyNext = pKey->next; + reg_unload_key(reg, pKey); + pKey = pKeyNext; + } + + free(reg->root_key); + } } Reg* reg_open(BOOL read_only) { - Reg* reg; - reg = (Reg*)malloc(sizeof(Reg)); + Reg* reg = (Reg*)calloc(1, sizeof(Reg)); if (!reg) return NULL; @@ -414,9 +485,7 @@ Reg* reg_open(BOOL read_only) reg->filename = WINPR_HKLM_HIVE; if (reg->read_only) - { reg->fp = winpr_fopen(reg->filename, "r"); - } else { reg->fp = winpr_fopen(reg->filename, "r+"); @@ -426,25 +495,22 @@ Reg* reg_open(BOOL read_only) } if (!reg->fp) - { - free(reg); - return NULL; - } + goto fail; - reg->root_key = (RegKey*)malloc(sizeof(RegKey)); + reg->root_key = (RegKey*)calloc(1, sizeof(RegKey)); if (!reg->root_key) - { - fclose(reg->fp); - free(reg); - return NULL; - } + goto fail; reg->root_key->values = NULL; reg->root_key->subkeys = NULL; reg->root_key->name = "HKEY_LOCAL_MACHINE"; reg_load(reg); return reg; + +fail: + reg_close(reg); + return NULL; } void reg_close(Reg* reg) @@ -452,7 +518,8 @@ void reg_close(Reg* reg) if (reg) { reg_unload(reg); - fclose(reg->fp); + if (reg->fp) + fclose(reg->fp); free(reg); } } diff --git a/winpr/libwinpr/registry/registry_reg.h b/winpr/libwinpr/registry/registry_reg.h index 90db136..ab3b34f 100644 --- a/winpr/libwinpr/registry/registry_reg.h +++ b/winpr/libwinpr/registry/registry_reg.h @@ -30,7 +30,7 @@ struct _reg FILE* fp; char* line; char* next_line; - int line_length; + size_t line_length; char* buffer; char* filename; BOOL read_only; @@ -44,7 +44,8 @@ struct _reg_val RegVal* prev; RegVal* next; - union reg_data { + union reg_data + { DWORD dword; char* string; } data; diff --git a/winpr/libwinpr/utils/ssl.c b/winpr/libwinpr/utils/ssl.c index 74ef156..301f940 100644 --- a/winpr/libwinpr/utils/ssl.c +++ b/winpr/libwinpr/utils/ssl.c @@ -33,6 +33,10 @@ #include #include +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +#include +#endif + #include "../log.h" #define TAG WINPR_TAG("utils.ssl") @@ -242,9 +246,10 @@ static BOOL winpr_enable_fips(DWORD flags) WLog_ERR(TAG, "Openssl fips mode not available on openssl versions less than 1.0.1!"); return FALSE; #else - WLog_DBG(TAG, "Ensuring openssl fips mode is ENabled"); + WLog_DBG(TAG, "Ensuring openssl fips mode is enabled"); #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + OSSL_PROVIDER_load(NULL, "fips"); if (!EVP_default_properties_is_fips_enabled(NULL)) #else if (FIPS_mode() != 1) @@ -255,10 +260,10 @@ static BOOL winpr_enable_fips(DWORD flags) #else if (FIPS_mode_set(1)) #endif - WLog_INFO(TAG, "Openssl fips mode ENabled!"); + WLog_INFO(TAG, "Openssl fips mode enabled!"); else { - WLog_ERR(TAG, "Openssl fips mode ENable failed!"); + WLog_ERR(TAG, "Openssl fips mode enable failed!"); return FALSE; } } @@ -305,8 +310,15 @@ static BOOL CALLBACK _winpr_openssl_initialize(PINIT_ONCE once, PVOID param, PVO return FALSE; #endif + +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + /* The legacy provider is needed for MD4. */ + OSSL_PROVIDER_load(NULL, "legacy"); + OSSL_PROVIDER_load(NULL, "default"); +#endif + g_winpr_openssl_initialized_by_winpr = TRUE; - return winpr_enable_fips(flags); + return TRUE; } /* exported functions */ From 45f744e4b0adbac4d5418c37db216d78d3e76fad Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Sat, 26 Feb 2022 21:44:23 +0100 Subject: [PATCH 2/2] New upstream version 2.6.0+dfsg1 --- .travis.yml | 1 - CMakeLists.txt | 11 +- ChangeLog | 23 + .../ainput/CMakeLists.txt | 17 +- channels/ainput/ChannelOptions.cmake | 13 + channels/ainput/client/CMakeLists.txt | 34 + channels/ainput/client/ainput_main.c | 317 +++++++++ channels/ainput/client/ainput_main.h | 43 ++ channels/ainput/common/ainput_common.h | 81 +++ channels/ainput/server/CMakeLists.txt | 27 + channels/ainput/server/ainput_main.c | 546 +++++++++++++++ channels/audin/client/audin_main.c | 7 +- channels/audin/client/winmm/audin_winmm.c | 2 + channels/disp/server/disp_main.c | 36 +- channels/rdpdr/client/rdpdr_main.c | 15 +- channels/rdpei/server/rdpei_main.c | 8 +- channels/rdpgfx/rdpgfx_common.c | 15 +- channels/server/channels.c | 12 + channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c | 2 + ci/cmake-preloads/config-android.txt | 7 - ci/cmake-preloads/config-debian-squeeze.txt | 11 - ci/cmake-preloads/config-ios.txt | 7 - ci/cmake-preloads/config-linux-all.txt | 53 -- ci/cmake-preloads/config-macosx.txt | 8 - ci/cmake-preloads/config-ubuntu-1204.txt | 11 - ci/cmake-preloads/config-windows.txt | 6 - client/CMakeLists.txt | 5 +- client/X11/xf_client.c | 15 +- cmake/Findx264.cmake | 33 - cmake/iOSToolchain.cmake | 196 ------ config.h.in | 6 +- docs/README.android | 86 --- docs/README.ios | 100 --- docs/README.macOS | 7 - include/freerdp/channels/ainput.h | 61 ++ include/freerdp/client/ainput.h | 38 + include/freerdp/server/ainput.h | 114 +++ libfreerdp/CMakeLists.txt | 10 +- libfreerdp/codec/dsp_ffmpeg.c | 4 + libfreerdp/codec/h264.c | 18 +- libfreerdp/codec/h264_mediacodec.c | 649 ++++++++++++++++++ libfreerdp/codec/h264_x264.c | 117 ---- libfreerdp/codec/progressive.c | 45 +- libfreerdp/core/freerdp.c | 3 +- scripts/android-build-32.conf | 29 - scripts/android-build-64.conf | 29 - scripts/android-build-common.sh | 292 -------- scripts/android-build-freerdp.sh | 168 ----- scripts/android-build-jpeg.sh | 40 -- scripts/android-build-openh264.sh | 64 -- scripts/android-build-openssl.sh | 77 --- scripts/android-build.conf | 29 - uwac/libuwac/uwac-priv.h | 8 + uwac/libuwac/uwac-window.c | 14 +- winpr/CMakeLists.txt | 2 +- winpr/libwinpr/crt/CMakeLists.txt | 2 +- winpr/libwinpr/sspicli/sspicli.c | 73 +- .../synch/test/TestSynchMultipleThreads.c | 66 +- winpr/libwinpr/utils/sam.c | 26 +- 59 files changed, 2220 insertions(+), 1519 deletions(-) rename cmake/ConfigOptionsAndroid.cmake => channels/ainput/CMakeLists.txt (58%) create mode 100644 channels/ainput/ChannelOptions.cmake create mode 100644 channels/ainput/client/CMakeLists.txt create mode 100644 channels/ainput/client/ainput_main.c create mode 100644 channels/ainput/client/ainput_main.h create mode 100644 channels/ainput/common/ainput_common.h create mode 100644 channels/ainput/server/CMakeLists.txt create mode 100644 channels/ainput/server/ainput_main.c delete mode 100644 ci/cmake-preloads/config-android.txt delete mode 100644 ci/cmake-preloads/config-debian-squeeze.txt delete mode 100644 ci/cmake-preloads/config-ios.txt delete mode 100644 ci/cmake-preloads/config-linux-all.txt delete mode 100644 ci/cmake-preloads/config-macosx.txt delete mode 100644 ci/cmake-preloads/config-ubuntu-1204.txt delete mode 100644 ci/cmake-preloads/config-windows.txt delete mode 100644 cmake/Findx264.cmake delete mode 100644 cmake/iOSToolchain.cmake delete mode 100644 docs/README.android delete mode 100644 docs/README.ios delete mode 100644 docs/README.macOS create mode 100644 include/freerdp/channels/ainput.h create mode 100644 include/freerdp/client/ainput.h create mode 100644 include/freerdp/server/ainput.h create mode 100644 libfreerdp/codec/h264_mediacodec.c delete mode 100644 libfreerdp/codec/h264_x264.c delete mode 100644 scripts/android-build-32.conf delete mode 100644 scripts/android-build-64.conf delete mode 100644 scripts/android-build-common.sh delete mode 100755 scripts/android-build-freerdp.sh delete mode 100755 scripts/android-build-jpeg.sh delete mode 100755 scripts/android-build-openh264.sh delete mode 100755 scripts/android-build-openssl.sh delete mode 100644 scripts/android-build.conf diff --git a/.travis.yml b/.travis.yml index 615a6d4..b5dc259 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,6 @@ addons: - libgsm1-dev - libavcodec-dev - libavutil-dev - - libx264-dev - libxext-dev - ninja-build - libsystemd-dev diff --git a/CMakeLists.txt b/CMakeLists.txt index 22c0347..967304e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.5.0") +set(RAW_VERSION_STRING "2.6.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) @@ -652,6 +652,7 @@ if(UNIX OR CYGWIN) include(CheckFunctionExists) check_function_exists(getlogin_r HAVE_GETLOGIN_R) + check_function_exists(getpwuid_r HAVE_GETPWUID_R) else() set(X11_FEATURE_TYPE "DISABLED") set(WAYLAND_FEATURE_TYPE "DISABLED") @@ -719,10 +720,6 @@ set(JPEG_FEATURE_TYPE "OPTIONAL") set(JPEG_FEATURE_PURPOSE "codec") set(JPEG_FEATURE_DESCRIPTION "use JPEG library") -set(X264_FEATURE_TYPE "OPTIONAL") -set(X264_FEATURE_PURPOSE "codec") -set(X264_FEATURE_DESCRIPTION "use x264 library") - set(OPENH264_FEATURE_TYPE "OPTIONAL") set(OPENH264_FEATURE_PURPOSE "codec") set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library") @@ -808,7 +805,6 @@ if(ANDROID) set(PULSE_FEATURE_TYPE "DISABLED") set(CUPS_FEATURE_TYPE "DISABLED") set(PCSC_FEATURE_TYPE "DISABLED") - set(FFMPEG_FEATURE_TYPE "DISABLED") set(VAAPI_FEATURE_TYPE "DISABLED") set(OPENSLES_FEATURE_TYPE "REQUIRED") endif() @@ -831,7 +827,6 @@ 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(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) -find_feature(x264 ${X264_FEATURE_TYPE} ${X264_FEATURE_PURPOSE} ${X264_FEATURE_DESCRIPTION}) find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION}) find_feature(OpenCL ${OPENCL_FEATURE_TYPE} ${OPENCL_FEATURE_PURPOSE} ${OPENCL_FEATURE_DESCRIPTION}) find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION}) @@ -917,7 +912,7 @@ if(MBEDTLS_FOUND) add_definitions("-DWITH_MBEDTLS") endif() -if (WITH_X264 OR WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG) +if (WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG OR WITH_MEDIACODEC) set(WITH_GFX_H264 ON) else() set(WITH_GFX_H264 OFF) diff --git a/ChangeLog b/ChangeLog index bf4e500..b7c7c4f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +# 2022-02-22 Version 2.6.0 + +Noteworthy changes: +* Backported android FFMPEG build scripts +* Updated android build dependencies + +Fixed issues: +* Backported #7303: Fix PDU length for RDPINPUT_PROTOCOL_V300 +* Backported #7658: Sanitize optional physical monitor size values +* Backported #7426: Wayland memory corruption +* Backported #7293: Remove unused codec x264 +* Backported #7541: Allow resolutions larger 2048x2048 +* Backported #7574: FFMPEG 5.0 support +* Backported #7578: FFMPEG 5.0 support +* Backported #7580: Fixed device hotplugging +* Backported #7583: GetUserNameExA: Prefer getpwuid_r over getlogin_r over getlogin +* Backported #7585: Android Mediacodec support + +Important notes: + +For a complete and detailed change log since the last release run: +git log 2.5.0..2.6.0 + # 2022-01-12 Version 2.5.0 Noteworthy changes: diff --git a/cmake/ConfigOptionsAndroid.cmake b/channels/ainput/CMakeLists.txt similarity index 58% rename from cmake/ConfigOptionsAndroid.cmake rename to channels/ainput/CMakeLists.txt index 07dd604..b1d1a6a 100644 --- a/cmake/ConfigOptionsAndroid.cmake +++ b/channels/ainput/CMakeLists.txt @@ -1,7 +1,8 @@ -# FreeRDP cmake android options +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script # -# Copyright 2013 Thincast Technologies GmbH -# Copyright 2013 Bernhard Miklautz +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,8 +16,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -option(WITH_OPENSLES "Enable sound and microphone redirection using OpenSLES" ON) +define_channel("ainput") -set(ANDROID_APP_TARGET_SDK 21 CACHE STRING "Application target android SDK") -set(ANDROID_APP_MIN_SDK 14 CACHE STRING "Application minimum android SDK requirement") +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/ainput/ChannelOptions.cmake b/channels/ainput/ChannelOptions.cmake new file mode 100644 index 0000000..eafc6c0 --- /dev/null +++ b/channels/ainput/ChannelOptions.cmake @@ -0,0 +1,13 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "ainput" TYPE "dynamic" + DESCRIPTION "Advanced Input Virtual Channel Extension" + SPECIFICATIONS "[XXXXX]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) + diff --git a/channels/ainput/client/CMakeLists.txt b/channels/ainput/client/CMakeLists.txt new file mode 100644 index 0000000..4cf2d22 --- /dev/null +++ b/channels/ainput/client/CMakeLists.txt @@ -0,0 +1,34 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH +# +# 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("ainput") + +set(${MODULE_PREFIX}_SRCS + ainput_main.c + ainput_main.h) + +include_directories(..) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${PROJECT_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() + +target_link_libraries(${MODULE_NAME} winpr) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c new file mode 100644 index 0000000..bf4ce26 --- /dev/null +++ b/channels/ainput/client/ainput_main.c @@ -0,0 +1,317 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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 "ainput_main.h" +#include +#include +#include + +#include "../common/ainput_common.h" + +#define WINPR_ASSERT(x) assert(x) + +#define TAG CHANNELS_TAG("ainput.client") + +typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK; +struct AINPUT_CHANNEL_CALLBACK_ +{ + IWTSVirtualChannelCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + IWTSVirtualChannel* channel; +}; + +typedef struct AINPUT_LISTENER_CALLBACK_ AINPUT_LISTENER_CALLBACK; +struct AINPUT_LISTENER_CALLBACK_ +{ + IWTSListenerCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + AINPUT_CHANNEL_CALLBACK* channel_callback; +}; + +typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN; +struct AINPUT_PLUGIN_ +{ + IWTSPlugin iface; + + AINPUT_LISTENER_CALLBACK* listener_callback; + IWTSListener* listener; + UINT32 MajorVersion; + UINT32 MinorVersion; + BOOL initialized; +}; + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) +{ + UINT16 type; + AINPUT_PLUGIN* ainput; + AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback; + + WINPR_ASSERT(callback); + WINPR_ASSERT(data); + + ainput = (AINPUT_PLUGIN*)callback->plugin; + WINPR_ASSERT(ainput); + + if (Stream_GetRemainingLength(data) < 2) + return ERROR_NO_DATA; + Stream_Read_UINT16(data, type); + switch (type) + { + case MSG_AINPUT_VERSION: + if (Stream_GetRemainingLength(data) < 8) + return ERROR_NO_DATA; + Stream_Read_UINT32(data, ainput->MajorVersion); + Stream_Read_UINT32(data, ainput->MinorVersion); + break; + default: + WLog_WARN(TAG, "Received unsupported message type 0x%04" PRIx16, type); + break; + } + + return CHANNEL_RC_OK; +} + +static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y) +{ + AINPUT_PLUGIN* ainput; + AINPUT_CHANNEL_CALLBACK* callback; + BYTE buffer[32] = { 0 }; + UINT64 time; + wStream sbuffer = { 0 }; + wStream* s = &sbuffer; + + Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); + + WINPR_ASSERT(s); + WINPR_ASSERT(context); + + time = GetTickCount64(); + ainput = (AINPUT_PLUGIN*)context->handle; + WINPR_ASSERT(ainput); + WINPR_ASSERT(ainput->listener_callback); + + if (ainput->MajorVersion != AINPUT_VERSION_MAJOR) + { + WLog_WARN(TAG, "Unsupported channel version %" PRIu32 ".%" PRIu32 ", aborting.", + ainput->MajorVersion, ainput->MinorVersion); + return CHANNEL_RC_UNSUPPORTED_VERSION; + } + callback = ainput->listener_callback->channel_callback; + WINPR_ASSERT(callback); + + { + char buffer[128] = { 0 }; + WLog_VRB(TAG, "[%s] sending timestamp=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32, + __FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y); + } + + /* Message type */ + Stream_Write_UINT16(s, MSG_AINPUT_MOUSE); + + /* Event data */ + Stream_Write_UINT64(s, time); + Stream_Write_UINT64(s, flags); + Stream_Write_INT32(s, x); + Stream_Write_INT32(s, y); + Stream_SealLength(s); + + /* ainput back what we have received. AINPUT does not have any message IDs. */ + WINPR_ASSERT(callback->channel); + WINPR_ASSERT(callback->channel->Write); + return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s), + NULL); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback) +{ + AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback; + + free(callback); + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) +{ + AINPUT_CHANNEL_CALLBACK* callback; + AINPUT_LISTENER_CALLBACK* listener_callback = (AINPUT_LISTENER_CALLBACK*)pListenerCallback; + + WINPR_ASSERT(listener_callback); + WINPR_UNUSED(Data); + WINPR_UNUSED(pbAccept); + + callback = (AINPUT_CHANNEL_CALLBACK*)calloc(1, sizeof(AINPUT_CHANNEL_CALLBACK)); + + if (!callback) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + callback->iface.OnDataReceived = ainput_on_data_received; + callback->iface.OnClose = ainput_on_close; + callback->plugin = listener_callback->plugin; + callback->channel_mgr = listener_callback->channel_mgr; + callback->channel = pChannel; + listener_callback->channel_callback = callback; + + *ppCallback = &callback->iface; + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) +{ + UINT status; + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin; + + WINPR_ASSERT(ainput); + + if (ainput->initialized) + { + WLog_ERR(TAG, "[%s] channel initialized twice, aborting", AINPUT_DVC_CHANNEL_NAME); + return ERROR_INVALID_DATA; + } + ainput->listener_callback = + (AINPUT_LISTENER_CALLBACK*)calloc(1, sizeof(AINPUT_LISTENER_CALLBACK)); + + if (!ainput->listener_callback) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + ainput->listener_callback->iface.OnNewChannelConnection = ainput_on_new_channel_connection; + ainput->listener_callback->plugin = pPlugin; + ainput->listener_callback->channel_mgr = pChannelMgr; + + status = pChannelMgr->CreateListener(pChannelMgr, AINPUT_DVC_CHANNEL_NAME, 0, + &ainput->listener_callback->iface, &ainput->listener); + + ainput->listener->pInterface = ainput->iface.pInterface; + ainput->initialized = status == CHANNEL_RC_OK; + return status; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin) +{ + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin; + if (ainput && ainput->listener_callback) + { + IWTSVirtualChannelManager* mgr = ainput->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, ainput->listener); + } + if (ainput) + { + free(ainput->listener_callback); + free(ainput->iface.pInterface); + } + free(ainput); + + return CHANNEL_RC_OK; +} + +#ifdef BUILTIN_CHANNELS +#define DVCPluginEntry ainput_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +{ + UINT status = CHANNEL_RC_OK; + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "ainput"); + + if (!ainput) + { + AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext)); + ainput = (AINPUT_PLUGIN*)calloc(1, sizeof(AINPUT_PLUGIN)); + + if (!ainput || !context) + { + free(context); + free(ainput); + + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + ainput->iface.Initialize = ainput_plugin_initialize; + ainput->iface.Terminated = ainput_plugin_terminated; + + context->handle = (void*)ainput; + context->AInputSendInputEvent = ainput_send_input_event; + ainput->iface.pInterface = (void*)context; + + status = pEntryPoints->RegisterPlugin(pEntryPoints, AINPUT_CHANNEL_NAME, &ainput->iface); + } + + return status; +} diff --git a/channels/ainput/client/ainput_main.h b/channels/ainput/client/ainput_main.h new file mode 100644 index 0000000..8a19ad9 --- /dev/null +++ b/channels/ainput/client/ainput_main.h @@ -0,0 +1,43 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_AINPUT_CLIENT_MAIN_H +#define FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#define DVC_TAG CHANNELS_TAG("ainput.client") +#ifdef WITH_DEBUG_DVC +#define DEBUG_DVC(...) WLog_DBG(DVC_TAG, __VA_ARGS__) +#else +#define DEBUG_DVC(...) \ + do \ + { \ + } while (0) +#endif + +#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H */ diff --git a/channels/ainput/common/ainput_common.h b/channels/ainput/common/ainput_common.h new file mode 100644 index 0000000..bc1be04 --- /dev/null +++ b/channels/ainput/common/ainput_common.h @@ -0,0 +1,81 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_INT_AINPUT_COMMON_H +#define FREERDP_INT_AINPUT_COMMON_H + +#include +#include + +#include + +static INLINE void ainput_append(char* buffer, size_t size, const char* what, BOOL separator) +{ + size_t have; + size_t toadd; + + assert(buffer || (size == 0)); + assert(what); + + have = strnlen(buffer, size); + toadd = strlen(what); + if (have > 0) + toadd += 1; + + if (size - have < toadd + 1) + return; + + if (have > 0) + strcat(buffer, separator ? "|" : " "); + strcat(buffer, what); +} + +static INLINE const char* ainput_flags_to_string(UINT64 flags, char* buffer, size_t size) +{ + char number[32] = { 0 }; + + if (flags & AINPUT_FLAGS_HAVE_REL) + ainput_append(buffer, size, "AINPUT_FLAGS_HAVE_REL", TRUE); + if (flags & AINPUT_FLAGS_WHEEL) + ainput_append(buffer, size, "AINPUT_FLAGS_WHEEL", TRUE); + if (flags & AINPUT_FLAGS_MOVE) + ainput_append(buffer, size, "AINPUT_FLAGS_MOVE", TRUE); + if (flags & AINPUT_FLAGS_DOWN) + ainput_append(buffer, size, "AINPUT_FLAGS_DOWN", TRUE); + if (flags & AINPUT_FLAGS_REL) + ainput_append(buffer, size, "AINPUT_FLAGS_REL", TRUE); + if (flags & AINPUT_FLAGS_BUTTON1) + ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON1", TRUE); + if (flags & AINPUT_FLAGS_BUTTON2) + ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON2", TRUE); + if (flags & AINPUT_FLAGS_BUTTON3) + ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON3", TRUE); + if (flags & AINPUT_XFLAGS_BUTTON1) + ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON1", TRUE); + if (flags & AINPUT_XFLAGS_BUTTON2) + ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON2", TRUE); + + _snprintf(number, sizeof(number), "[0x%08" PRIx64 "]", flags); + ainput_append(buffer, size, number, FALSE); + + return buffer; +} + +#endif /* FREERDP_INT_AINPUT_COMMON_H */ diff --git a/channels/ainput/server/CMakeLists.txt b/channels/ainput/server/CMakeLists.txt new file mode 100644 index 0000000..59be263 --- /dev/null +++ b/channels/ainput/server/CMakeLists.txt @@ -0,0 +1,27 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH +# +# 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_server("ainput") + +set(${MODULE_PREFIX}_SRCS + ainput_main.c) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") + +target_link_libraries(${MODULE_NAME} freerdp) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c new file mode 100644 index 0000000..670b668 --- /dev/null +++ b/channels/ainput/server/ainput_main.c @@ -0,0 +1,546 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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 "../common/ainput_common.h" + +#define WINPR_ASSERT(x) assert(x) + +#define TAG CHANNELS_TAG("ainput.server") + +typedef enum +{ + AINPUT_INITIAL, + AINPUT_OPENED, + AINPUT_VERSION_SENT, +} eAInputChannelState; + +typedef struct +{ + ainput_server_context context; + + BOOL opened; + + HANDLE stopEvent; + + HANDLE thread; + void* ainput_channel; + + DWORD SessionId; + + BOOL isOpened; + BOOL externalThread; + + /* Channel state */ + eAInputChannelState state; + + wStream* buffer; +} ainput_server; + +static UINT ainput_server_context_poll(ainput_server_context* context); +static BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle); +static UINT ainput_server_context_poll_int(ainput_server_context* context); + +static BOOL ainput_server_is_open(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + return ainput->isOpened; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_server_open_channel(ainput_server* ainput) +{ + DWORD Error; + HANDLE hEvent; + DWORD StartTick; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + + WINPR_ASSERT(ainput); + + if (WTSQuerySessionInformationA(ainput->context.vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return ERROR_INTERNAL_ERROR; + } + + ainput->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + hEvent = WTSVirtualChannelManagerGetEventHandle(ainput->context.vcm); + StartTick = GetTickCount(); + + while (ainput->ainput_channel == NULL) + { + if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED) + { + Error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error); + return Error; + } + + ainput->ainput_channel = WTSVirtualChannelOpenEx(ainput->SessionId, AINPUT_DVC_CHANNEL_NAME, + WTS_CHANNEL_OPTION_DYNAMIC); + + if (ainput->ainput_channel) + break; + + Error = GetLastError(); + + if (Error == ERROR_NOT_FOUND) + break; + + if (GetTickCount() - StartTick > 5000) + break; + } + + return ainput->ainput_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; +} + +static UINT ainput_server_send_version(ainput_server* ainput) +{ + ULONG written; + wStream* s; + + WINPR_ASSERT(ainput); + + s = ainput->buffer; + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + if (!Stream_EnsureCapacity(s, 10)) + return ERROR_OUTOFMEMORY; + + Stream_Write_UINT16(s, MSG_AINPUT_VERSION); + Stream_Write_UINT32(s, AINPUT_VERSION_MAJOR); /* Version (4 bytes) */ + Stream_Write_UINT32(s, AINPUT_VERSION_MINOR); /* Version (4 bytes) */ + + WINPR_ASSERT(Stream_GetPosition(s) <= ULONG_MAX); + if (!WTSVirtualChannelWrite(ainput->ainput_channel, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_GetPosition(s), &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + return ERROR_INTERNAL_ERROR; + } + + return CHANNEL_RC_OK; +} + +static UINT ainput_server_recv_mouse_event(ainput_server* ainput, wStream* s) +{ + UINT error = CHANNEL_RC_OK; + UINT64 flags, time; + INT32 x, y; + char buffer[128] = { 0 }; + + WINPR_ASSERT(ainput); + WINPR_ASSERT(s); + + if (Stream_GetRemainingLength(s) < 24) + return ERROR_NO_DATA; + + Stream_Read_UINT64(s, time); + Stream_Read_UINT64(s, flags); + Stream_Read_INT32(s, x); + Stream_Read_INT32(s, y); + + WLog_VRB(TAG, "[%s] received: time=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32, + __FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y); + IFCALLRET(ainput->context.MouseEvent, error, &ainput->context, time, flags, x, y); + + return error; +} + +static HANDLE ainput_server_get_channel_handle(ainput_server* ainput) +{ + BYTE* buffer = NULL; + DWORD BytesReturned = 0; + HANDLE ChannelEvent = NULL; + + WINPR_ASSERT(ainput); + + if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + return ChannelEvent; +} + +static DWORD WINAPI ainput_server_thread_func(LPVOID arg) +{ + DWORD nCount; + HANDLE events[2] = { 0 }; + ainput_server* ainput = (ainput_server*)arg; + UINT error = CHANNEL_RC_OK; + DWORD status; + + WINPR_ASSERT(ainput); + + nCount = 0; + events[nCount++] = ainput->stopEvent; + + while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0)) + { + switch (ainput->state) + { + case AINPUT_OPENED: + events[1] = ainput_server_get_channel_handle(ainput); + nCount = 2; + status = WaitForMultipleObjects(nCount, events, FALSE, 100); + switch (status) + { + case WAIT_TIMEOUT: + case WAIT_OBJECT_0 + 1: + case WAIT_OBJECT_0: + error = ainput_server_context_poll_int(&ainput->context); + + case WAIT_FAILED: + default: + error = ERROR_INTERNAL_ERROR; + break; + } + break; + case AINPUT_VERSION_SENT: + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + switch (status) + { + case WAIT_TIMEOUT: + case WAIT_OBJECT_0 + 1: + case WAIT_OBJECT_0: + error = ainput_server_context_poll_int(&ainput->context); + + case WAIT_FAILED: + default: + error = ERROR_INTERNAL_ERROR; + break; + } + break; + default: + error = ainput_server_context_poll_int(&ainput->context); + break; + } + } + + WTSVirtualChannelClose(ainput->ainput_channel); + ainput->ainput_channel = NULL; + + if (error && ainput->context.rdpcontext) + setChannelError(ainput->context.rdpcontext, error, + "ainput_server_thread_func reported an error"); + + ExitThread(error); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_server_open(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + + if (!ainput->externalThread && (ainput->thread == NULL)) + { + ainput->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!ainput->stopEvent) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return ERROR_INTERNAL_ERROR; + } + + ainput->thread = CreateThread(NULL, 0, ainput_server_thread_func, ainput, 0, NULL); + if (!ainput->thread) + { + WLog_ERR(TAG, "CreateEvent failed!"); + CloseHandle(ainput->stopEvent); + ainput->stopEvent = NULL; + return ERROR_INTERNAL_ERROR; + } + } + ainput->isOpened = TRUE; + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_server_close(ainput_server_context* context) +{ + UINT error = CHANNEL_RC_OK; + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + + if (!ainput->externalThread && ainput->thread) + { + SetEvent(ainput->stopEvent); + + if (WaitForSingleObject(ainput->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); + return error; + } + + CloseHandle(ainput->thread); + CloseHandle(ainput->stopEvent); + ainput->thread = NULL; + ainput->stopEvent = NULL; + } + if (ainput->externalThread) + { + if (ainput->state != AINPUT_INITIAL) + { + WTSVirtualChannelClose(ainput->ainput_channel); + ainput->ainput_channel = NULL; + ainput->state = AINPUT_INITIAL; + } + } + ainput->isOpened = FALSE; + + return error; +} + +static UINT ainput_server_initialize(ainput_server_context* context, BOOL externalThread) +{ + UINT error = CHANNEL_RC_OK; + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + + if (ainput->isOpened) + { + WLog_WARN(TAG, "Application error: AINPUT channel already initialized, calling in this " + "state is not possible!"); + return ERROR_INVALID_STATE; + } + ainput->externalThread = externalThread; + return error; +} + +ainput_server_context* ainput_server_context_new(HANDLE vcm) +{ + ainput_server* ainput = (ainput_server*)calloc(1, sizeof(ainput_server)); + + if (!ainput) + return NULL; + + ainput->context.vcm = vcm; + ainput->context.Open = ainput_server_open; + ainput->context.IsOpen = ainput_server_is_open; + ainput->context.Close = ainput_server_close; + ainput->context.Initialize = ainput_server_initialize; + ainput->context.Poll = ainput_server_context_poll; + ainput->context.ChannelHandle = ainput_server_context_handle; + + ainput->buffer = Stream_New(NULL, 4096); + if (!ainput->buffer) + goto fail; + return &ainput->context; +fail: + ainput_server_context_free(ainput); + return NULL; +} + +void ainput_server_context_free(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + if (ainput) + { + ainput_server_close(context); + Stream_Free(ainput->buffer, TRUE); + } + free(ainput); +} + +static UINT ainput_process_message(ainput_server* ainput) +{ + BOOL rc; + UINT error = ERROR_INTERNAL_ERROR; + ULONG BytesReturned; + UINT16 MessageId; + wStream* s; + + WINPR_ASSERT(ainput); + WINPR_ASSERT(ainput->ainput_channel); + + s = ainput->buffer; + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + rc = WTSVirtualChannelRead(ainput->ainput_channel, 0, NULL, 0, &BytesReturned); + if (!rc) + goto out; + + if (BytesReturned < 2) + { + error = CHANNEL_RC_OK; + goto out; + } + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto out; + } + + if (WTSVirtualChannelRead(ainput->ainput_channel, 0, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + goto out; + } + + Stream_SetLength(s, BytesReturned); + Stream_Read_UINT16(s, MessageId); + + switch (MessageId) + { + case MSG_AINPUT_MOUSE: + error = ainput_server_recv_mouse_event(ainput, s); + break; + + default: + WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %" PRIu8 "", MessageId); + break; + } + +out: + if (error) + WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); + + return error; +} + +BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle) +{ + ainput_server* ainput = (ainput_server*)context; + WINPR_ASSERT(ainput); + WINPR_ASSERT(handle); + + if (!ainput->externalThread) + return FALSE; + if (ainput->state == AINPUT_INITIAL) + return FALSE; + *handle = ainput_server_get_channel_handle(ainput); + return TRUE; +} + +UINT ainput_server_context_poll_int(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + UINT error = ERROR_INTERNAL_ERROR; + + WINPR_ASSERT(ainput); + + switch (ainput->state) + { + case AINPUT_INITIAL: + error = ainput_server_open_channel(ainput); + if (error) + WLog_ERR(TAG, "ainput_server_open_channel failed with error %" PRIu32 "!", error); + else + ainput->state = AINPUT_OPENED; + break; + case AINPUT_OPENED: + { + BYTE* buffer = NULL; + DWORD BytesReturned = 0; + + if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer, + &BytesReturned) != TRUE) + { + WLog_ERR(TAG, "WTSVirtualChannelReady failed,"); + } + else + { + if (*buffer != 0) + { + error = ainput_server_send_version(ainput); + if (error) + WLog_ERR(TAG, "audin_server_send_version failed with error %" PRIu32 "!", + error); + else + ainput->state = AINPUT_VERSION_SENT; + } + else + error = CHANNEL_RC_OK; + } + WTSFreeMemory(buffer); + } + break; + case AINPUT_VERSION_SENT: + error = ainput_process_message(ainput); + break; + + default: + WLog_ERR(TAG, "AINPUT chanel is in invalid state %d", ainput->state); + break; + } + + return error; +} + +UINT ainput_server_context_poll(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + if (!ainput->externalThread) + return ERROR_INTERNAL_ERROR; + return ainput_server_context_poll_int(context); +} diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index a5b9416..81a6e8f 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -444,11 +444,8 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb return FALSE; } - if (!supported) - { - if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format)) - return FALSE; - } + if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format)) + return FALSE; IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c index 92a7785..7538672 100644 --- a/channels/audin/client/winmm/audin_winmm.c +++ b/channels/audin/client/winmm/audin_winmm.c @@ -345,7 +345,9 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for if (ppwfx->nBlockAlign != 2) { ppwfx->nBlockAlign = 2; + ppwfx->nAvgBytesPerSec = ppwfx->nSamplesPerSec * ppwfx->nBlockAlign; } + if (!test_format_supported(ppwfx)) return ERROR_INVALID_PARAMETER; winmm->pwfx_cur = ppwfx; diff --git a/channels/disp/server/disp_main.c b/channels/disp/server/disp_main.c index a764acd..64e96c3 100644 --- a/channels/disp/server/disp_main.c +++ b/channels/disp/server/disp_main.c @@ -72,6 +72,24 @@ error: return NULL; } +static void disp_server_sanitize_monitor_layout(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor) +{ + if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH || + monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH || + monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT || + monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT) + { + if (monitor->PhysicalWidth != 0 || monitor->PhysicalHeight != 0) + WLog_DBG( + TAG, + "Sanitizing invalid physical monitor size. Old physical monitor size: [%" PRIu32 + ", %" PRIu32 "]", + monitor->PhysicalWidth, monitor->PhysicalHeight); + + monitor->PhysicalWidth = monitor->PhysicalHeight = 0; + } +} + static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor) { if (monitor->Width < DISPLAY_CONTROL_MIN_MONITOR_WIDTH || @@ -88,22 +106,6 @@ static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* return FALSE; } - if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH || - monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH) - { - WLog_WARN(TAG, "Received invalid value for monitor->PhysicalWidth: %" PRIu32 "", - monitor->PhysicalWidth); - return FALSE; - } - - if (monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT || - monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT) - { - WLog_WARN(TAG, "Received invalid value for monitor->Height: %" PRIu32 "", - monitor->PhysicalHeight); - return FALSE; - } - switch (monitor->Orientation) { case ORIENTATION_LANDSCAPE: @@ -183,6 +185,8 @@ static UINT disp_recv_display_control_monitor_layout_pdu(wStream* s, DispServerC Stream_Read_UINT32(s, monitor->Orientation); /* Orientation (4 bytes) */ Stream_Read_UINT32(s, monitor->DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */ Stream_Read_UINT32(s, monitor->DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */ + + disp_server_sanitize_monitor_layout(monitor); WLog_DBG(TAG, "\t%d : Flags: 0x%08" PRIX32 " Left/Top: (%" PRId32 ",%" PRId32 ") W/H=%" PRIu32 "x%" PRIu32 ")", diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 617ea42..309d24c 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -33,6 +33,8 @@ #include #include +#include + #include #include #include @@ -204,7 +206,6 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) drive.Type = RDPDR_DTYP_FILESYSTEM; drive.Path = drive_path; - drive_path[1] = '\0'; drive.automount = TRUE; drive.Name = drive_name; devman_load_device_service(rdpdr->devman, @@ -583,7 +584,6 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) #else - static const char* automountLocations[] = { "/run/user/%lu/gvfs", "/run/media/%s", "/media/%s", "/media", "/mnt" }; @@ -591,16 +591,13 @@ static BOOL isAutomountLocation(const char* path) { const size_t nrLocations = sizeof(automountLocations) / sizeof(automountLocations[0]); size_t x; - char buffer[MAX_PATH]; + char buffer[MAX_PATH] = { 0 }; uid_t uid = getuid(); char uname[MAX_PATH] = { 0 }; + ULONG size = sizeof(uname) - 1; -#ifndef HAVE_GETLOGIN_R - strncpy(uname, getlogin(), sizeof(uname)); -#else - if (getlogin_r(uname, sizeof(uname)) != 0) + if (!GetUserNameExA(NameSamCompatible, uname, &size)) return FALSE; -#endif if (!path) return FALSE; @@ -656,7 +653,7 @@ static void handle_mountpoint(hotplug_dev* dev_array, size_t* size, const char* if (isAutomountLocation(mountpoint) && (*size < MAX_USB_DEVICES)) { dev_array[*size].path = _strdup(mountpoint); - dev_array[*size + 1].to_add = TRUE; + dev_array[*size].to_add = TRUE; (*size)++; } } diff --git a/channels/rdpei/server/rdpei_main.c b/channels/rdpei/server/rdpei_main.c index 80ab4b6..1e2dfe2 100644 --- a/channels/rdpei/server/rdpei_main.c +++ b/channels/rdpei/server/rdpei_main.c @@ -612,6 +612,7 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version, { ULONG written; RdpeiServerPrivate* priv = context->priv; + UINT32 pduLen = 4; if (priv->automataState != STATE_INITIAL) { @@ -621,14 +622,17 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version, Stream_SetPosition(priv->outputStream, 0); - if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4)) + if (version >= RDPINPUT_PROTOCOL_V300) + pduLen += 4; + + if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen)) { WLog_ERR(TAG, "Stream_EnsureCapacity failed!"); return CHANNEL_RC_NO_MEMORY; } Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY); - Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4); + Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen); Stream_Write_UINT32(priv->outputStream, version); if (version >= RDPINPUT_PROTOCOL_V300) Stream_Write_UINT32(priv->outputStream, features); diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c index 79bbc9e..c0bc0b0 100644 --- a/channels/rdpgfx/rdpgfx_common.c +++ b/channels/rdpgfx/rdpgfx_common.c @@ -1,4 +1,4 @@ -/** +/** * FreeRDP: A Remote Desktop Protocol Implementation * Graphics Pipeline Extension * @@ -24,9 +24,12 @@ #endif #include +#include #include #include +#define WINPR_ASSERT(x) assert(x) + #define TAG CHANNELS_TAG("rdpgfx.common") #include "rdpgfx_common.h" @@ -110,6 +113,9 @@ const char* rdpgfx_get_codec_id_string(UINT16 codecId) */ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) { + WINPR_ASSERT(s); + WINPR_ASSERT(header); + if (Stream_GetRemainingLength(s) < 8) { WLog_ERR(TAG, "calloc failed!"); @@ -119,6 +125,13 @@ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */ Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */ Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */ + + if ((header->pduLength < 8) || (Stream_GetRemainingLength(s) < (header->pduLength - 8))) + { + WLog_ERR(TAG, "header->pduLength %u less than 8!", header->pduLength); + return ERROR_INVALID_DATA; + } + return CHANNEL_RC_OK; } diff --git a/channels/server/channels.c b/channels/server/channels.c index 40c55ee..3714c5e 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -53,6 +53,12 @@ #include #include +#if defined(CHANNEL_AINPUT_SERVER) +#include +#endif + +extern void freerdp_channels_dummy(void); + void freerdp_channels_dummy(void) { audin_server_context* audin; @@ -91,6 +97,12 @@ void freerdp_channels_dummy(void) rdpgfx_server_context_free(rdpgfx); disp = disp_server_context_new(NULL); disp_server_context_free(disp); +#if defined(CHANNEL_AINPUT_SERVER) + { + ainput_server_context* ainput = ainput_server_context_new(NULL); + ainput_server_context_free(ainput); + } +#endif } /** diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index 0444ad0..cf0aa9b 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -615,7 +615,9 @@ static void tsmf_ffmpeg_free(ITSMFDecoder* decoder) static INIT_ONCE g_Initialized = INIT_ONCE_STATIC_INIT; static BOOL CALLBACK InitializeAvCodecs(PINIT_ONCE once, PVOID param, PVOID* context) { +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100) avcodec_register_all(); +#endif return TRUE; } diff --git a/ci/cmake-preloads/config-android.txt b/ci/cmake-preloads/config-android.txt deleted file mode 100644 index bcb3446..0000000 --- a/ci/cmake-preloads/config-android.txt +++ /dev/null @@ -1,7 +0,0 @@ -message("PRELOADING android cache") -set(CMAKE_TOOLCHAIN_FILE "$ANDROID_NDK/build/cmake/android.toolchain.cmake" CACHE PATH "ToolChain file") -set(WITH_SANITIZE_ADDRESS ON) -set(FREERDP_EXTERNAL_SSL_PATH $ENV{ANDROID_SSL_PATH} CACHE PATH "android ssl") -# ANDROID_NDK and ANDROID_SDK must be set as environment variable -#set(ANDROID_NDK $ENV{ANDROID_SDK} CACHE PATH "Android NDK") -#set(ANDROID_SDK "${ANDROID_NDK}" CACHE PATH "android SDK") diff --git a/ci/cmake-preloads/config-debian-squeeze.txt b/ci/cmake-preloads/config-debian-squeeze.txt deleted file mode 100644 index c7319cf..0000000 --- a/ci/cmake-preloads/config-debian-squeeze.txt +++ /dev/null @@ -1,11 +0,0 @@ -message("PRELOADING cache") -set (WITH_MANPAGES OFF CACHE BOOL "man pages") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (WITH_CUPS OFF CACHE BOOL "CUPS printing") -set (WITH_GSSAPI ON CACHE BOOL "Kerberos support") -set (WITH_ALSA OFF CACHE BOOL "alsa audio") -set (WITH_FFMPEG OFF CACHE BOOL "ffmepg support") -set (WITH_XV OFF CACHE BOOL "xvideo support") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_XSHM OFF CACHE BOOL "build with xshm support") -set (WITH_SANITIZE_ADDRESS ON) diff --git a/ci/cmake-preloads/config-ios.txt b/ci/cmake-preloads/config-ios.txt deleted file mode 100644 index 886c36a..0000000 --- a/ci/cmake-preloads/config-ios.txt +++ /dev/null @@ -1,7 +0,0 @@ -message("PRELOADING iOS cache") -set (CMAKE_TOOLCHAIN_FILE "cmake/iOSToolchain.cmake" CACHE PATH "ToolChain file") -set (FREERDP_IOS_EXTERNAL_SSL_PATH $ENV{FREERDP_IOS_EXTERNAL_SSL_PATH} CACHE PATH "android ssl") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (IOS_PLATFORM "SIMULATOR" CACHE STRING "iso platfrorm to build") -set (WITH_SANITIZE_ADDRESS ON CACHE BOOL "build with address sanitizer") -set (WITH_CLIENT OFF CACHE BOOL "disable iOS client") diff --git a/ci/cmake-preloads/config-linux-all.txt b/ci/cmake-preloads/config-linux-all.txt deleted file mode 100644 index 4ba743e..0000000 --- a/ci/cmake-preloads/config-linux-all.txt +++ /dev/null @@ -1,53 +0,0 @@ -message("PRELOADING cache") -set (BUILD_TESTING ON CACHE BOOL "testing") -set (WITH_MANPAGES OFF CACHE BOOL "man pages") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_PULSE ON CACHE BOOL "pulse") -set (WITH_CHANNELS ON CACHE BOOL "channels") -set (BUILTIN_CHANNELS ON CACHE BOOL "static channels") -set (WITH_CUPS ON CACHE BOOL "cups") -set (WITH_WAYLAND ON CACHE BOOL "wayland") -set (WITH_GSSAPI ON CACHE BOOL "Kerberos support") -set (WITH_PCSC ON CACHE BOOL "PCSC") -set (WITH_JPEG ON CACHE BOOL "jpeg") -set (WITH_GSTREAMER_0_10 ON CACHE BOOL "gstreamer") -set (WITH_GSM ON CACHE BOOL "gsm") -set (CHANNEL_URBDRC ON CACHE BOOL "urbdrc") -set (CHANNEL_URBDRC_CLIENT ON CACHE BOOL "urbdrc client") -set (WITH_SERVER ON CACHE BOOL "server side") -set (WITH_DEBUG_ALL OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_CAPABILITIES OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_CERTIFICATE OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_CHANNELS OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_CLIPRDR OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RDPGFX OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_DVC OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_KBD OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_LICENSE OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_NEGO OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_NLA OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_NTLM OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RAIL OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RDP OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RDPEI OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_REDIR OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RDPDR OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RFX OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_SCARD OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_SND OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_SVC OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_THREADS OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_TIMEZONE OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_TRANSPORT OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_TSG OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_TSMF OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_WND OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_X11 OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_X11_CLIPRDR OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_X11_LOCAL_MOVESIZE OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_XV OFF CACHE BOOL "enable debug") -set (WITH_SAMPLE ON CACHE BOOL "samples") -set (WITH_NO_UNDEFINED ON CACHE BOOL "don't link with undefined symbols") -set (WITH_SANITIZE_ADDRESS ON) -set (WITH_PROXY_MODULES OFF CACHE BOOL "compile proxy modules") diff --git a/ci/cmake-preloads/config-macosx.txt b/ci/cmake-preloads/config-macosx.txt deleted file mode 100644 index a004dd9..0000000 --- a/ci/cmake-preloads/config-macosx.txt +++ /dev/null @@ -1,8 +0,0 @@ -message("PRELOADING mac cache") -set (WITH_MANPAGES OFF CACHE BOOL "man pages") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (WITH_CUPS ON CACHE BOOL "CUPS printing") -set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection") -set (WITH_X11 ON CACHE BOOL "Enable X11") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_SANITIZE_ADDRESS ON) diff --git a/ci/cmake-preloads/config-ubuntu-1204.txt b/ci/cmake-preloads/config-ubuntu-1204.txt deleted file mode 100644 index c7319cf..0000000 --- a/ci/cmake-preloads/config-ubuntu-1204.txt +++ /dev/null @@ -1,11 +0,0 @@ -message("PRELOADING cache") -set (WITH_MANPAGES OFF CACHE BOOL "man pages") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (WITH_CUPS OFF CACHE BOOL "CUPS printing") -set (WITH_GSSAPI ON CACHE BOOL "Kerberos support") -set (WITH_ALSA OFF CACHE BOOL "alsa audio") -set (WITH_FFMPEG OFF CACHE BOOL "ffmepg support") -set (WITH_XV OFF CACHE BOOL "xvideo support") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_XSHM OFF CACHE BOOL "build with xshm support") -set (WITH_SANITIZE_ADDRESS ON) diff --git a/ci/cmake-preloads/config-windows.txt b/ci/cmake-preloads/config-windows.txt deleted file mode 100644 index fcc78ae..0000000 --- a/ci/cmake-preloads/config-windows.txt +++ /dev/null @@ -1,6 +0,0 @@ -message("PRELOADING windows cache") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (WITH_SERVER "ON" CACHE BOOL "Build server binaries") -set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_SANITIZE_ADDRESS ON) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 7cba44e..af7606b 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -43,7 +43,10 @@ if(FREERDP_VENDOR AND WITH_CLIENT) add_subdirectory(iOS) endif() else() - add_subdirectory(Mac) + option(WITH_CLIENT_MAC "Build native mac client" ON) + if (WITH_CLIENT_MAC) + add_subdirectory(Mac) + endif() endif() endif() diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 78852a7..4bdad53 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -27,6 +27,7 @@ #endif #include +#include #include #include @@ -1183,20 +1184,12 @@ static BOOL xf_pre_connect(freerdp* instance) if (!settings->Username && !settings->CredentialsFromStdin && !settings->SmartcardLogon) { - int rc; char login_name[MAX_PATH] = { 0 }; + ULONG size = sizeof(login_name) - 1; -#ifdef HAVE_GETLOGIN_R - rc = getlogin_r(login_name, sizeof(login_name)); -#else - strncpy(login_name, getlogin(), sizeof(login_name)); - rc = 0; -#endif - if (rc == 0) + if (GetUserNameExA(NameSamCompatible, login_name, &size)) { - settings->Username = _strdup(login_name); - - if (!settings->Username) + if (!freerdp_settings_set_string(settings, FreeRDP_Username, login_name)) return FALSE; WLog_INFO(TAG, "No user name set. - Using login name: %s", settings->Username); diff --git a/cmake/Findx264.cmake b/cmake/Findx264.cmake deleted file mode 100644 index f8df475..0000000 --- a/cmake/Findx264.cmake +++ /dev/null @@ -1,33 +0,0 @@ - -if (X264_INCLUDE_DIR AND X264_LIBRARY) - set(X264_FIND_QUIETLY TRUE) -endif (X264_INCLUDE_DIR AND X264_LIBRARY) - -find_path(X264_INCLUDE_DIR NAMES x264.h - PATH_SUFFIXES include - HINTS ${X264_ROOT}) -find_library(X264_LIBRARY - NAMES x264 - PATH_SUFFIXES lib - HINTS ${X264_ROOT}) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(x264 DEFAULT_MSG X264_LIBRARY X264_INCLUDE_DIR) - -if (X264_INCLUDE_DIR AND X264_LIBRARY) - set(X264_FOUND TRUE) - set(X264_LIBRARIES ${X264_LIBRARY}) -endif (X264_INCLUDE_DIR AND X264_LIBRARY) - -if (X264_FOUND) - if (NOT X264_FIND_QUIETLY) - message(STATUS "Found x264: ${X264_LIBRARIES}") - endif (NOT X264_FIND_QUIETLY) -else (X264_FOUND) - if (X264_FIND_REQUIRED) - message(FATAL_ERROR "x264 was not found") - endif(X264_FIND_REQUIRED) -endif (X264_FOUND) - -mark_as_advanced(X264_INCLUDE_DIR X264_LIBRARY) - diff --git a/cmake/iOSToolchain.cmake b/cmake/iOSToolchain.cmake deleted file mode 100644 index 1824ecb..0000000 --- a/cmake/iOSToolchain.cmake +++ /dev/null @@ -1,196 +0,0 @@ -# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake -# files which are included with CMake 2.8.4 -# It has been altered for iOS development - -# Options: -# -# IOS_PLATFORM = OS (default) or SIMULATOR -# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders -# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. -# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. -# -# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder -# By default this location is automatcially chosen based on the IOS_PLATFORM value above. -# If set manually, it will override the default location and force the user of a particular Developer Platform -# -# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder -# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. -# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. -# If set manually, this will force the use of a specific SDK version - -# Macros: -# -# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE) -# A convenience macro for setting xcode specific properties on targets -# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1") -# -# find_host_package (PROGRAM ARGS) -# A macro used to find executable programs on the host system, not within the iOS environment. -# Thanks to the android-cmake project for providing the command - - -# Standard settings -set (CMAKE_SYSTEM_NAME Darwin) -set (CMAKE_SYSTEM_VERSION 1) -set (UNIX True) -set (APPLE True) -set (IOS True) - -# Required as of cmake 2.8.10 -#set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE) - -# Determine the cmake host system version so we know where to find the iOS SDKs -find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) -if (CMAKE_UNAME) - exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) - string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") -endif (CMAKE_UNAME) - -# Force the compilers to gcc for iOS -include (CMakeForceCompiler) -CMAKE_FORCE_C_COMPILER (/usr/bin/clang Apple) -CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++ Apple) -set(CMAKE_AR ar CACHE FILEPATH "" FORCE) - -# Skip the platform compiler checks for cross compiling -#set (CMAKE_CXX_COMPILER_WORKS TRUE) -#set (CMAKE_C_COMPILER_WORKS TRUE) - -# All iOS/Darwin specific settings - some may be redundant -set (CMAKE_SHARED_LIBRARY_PREFIX "lib") -set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") -set (CMAKE_SHARED_MODULE_PREFIX "lib") -set (CMAKE_SHARED_MODULE_SUFFIX ".so") -set (CMAKE_MODULE_EXISTS 1) -set (CMAKE_DL_LIBS "") - -set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") -set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") -set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") -set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") - -# Hidden visibilty is required for cxx on iOS -set (CMAKE_C_FLAGS_INIT "") -set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden -isysroot ${CMAKE_OSX_SYSROOT}") - -set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") -set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") - -set (CMAKE_PLATFORM_HAS_INSTALLNAME 1) -set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names") -set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names") -set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") -set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") -set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a") - -# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree -# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache -# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun) -# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex -if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) - find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool) -endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) - -# Setup iOS platform unless specified manually with IOS_PLATFORM -if (NOT DEFINED IOS_PLATFORM) - set (IOS_PLATFORM "OS") -endif (NOT DEFINED IOS_PLATFORM) -set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") - -# Check the platform selection and setup for developer root -if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") -elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") - set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") -else (${IOS_PLATFORM} STREQUAL "OS") - message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") -endif (${IOS_PLATFORM} STREQUAL "OS") - -# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT -# Note Xcode 4.3 changed the installation location, choose the most recent one available -set (XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) - if (EXISTS ${XCODE_POST_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) - elseif(EXISTS ${XCODE_PRE_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) - endif (EXISTS ${XCODE_POST_43_ROOT}) -endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) -set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") - -# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT -if (NOT DEFINED CMAKE_IOS_SDK_ROOT) - file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") - if (_CMAKE_IOS_SDKS) - list (SORT _CMAKE_IOS_SDKS) - list (REVERSE _CMAKE_IOS_SDKS) - list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) - else (_CMAKE_IOS_SDKS) - message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") - endif (_CMAKE_IOS_SDKS) - message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") -endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) -set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") - -# Set the sysroot default to the most recent SDK -set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") - -# set the architecture for iOS -# NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually -if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH armv7 armv7s) - set (CMAKE_SYSTEM_PROCESSOR armv7) -else (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH i386) - set (CMAKE_SYSTEM_PROCESSOR i386) -endif (${IOS_PLATFORM} STREQUAL "OS") - -set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") - -# Set the find root to the iOS developer roots and to user defined paths -set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") - -# default to searching for frameworks first -set (CMAKE_FIND_FRAMEWORK FIRST) - -# set up the default search directories for frameworks -set (CMAKE_SYSTEM_FRAMEWORK_PATH - ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks - ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks - ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks -) - -# only search the iOS sdks, not the remainder of the host filesystem -set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) -set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - - -# This little macro lets you set any XCode specific property -macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) - set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) -endmacro (set_xcode_property) - - -# This macro lets you find executable programs on the host system -macro (find_host_package) - set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) - set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) - set (IOS FALSE) - - find_package(${ARGN}) - - set (IOS TRUE) - set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) - set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endmacro (find_host_package) - diff --git a/config.h.in b/config.h.in index 2264e59..1f35d68 100644 --- a/config.h.in +++ b/config.h.in @@ -25,6 +25,7 @@ #cmakedefine HAVE_VALGRIND_MEMCHECK_H #cmakedefine HAVE_EXECINFO_H #cmakedefine HAVE_GETLOGIN_R +#cmakedefine HAVE_GETPWUID_R /* Features */ #cmakedefine SWRESAMPLE_FOUND @@ -63,9 +64,9 @@ #cmakedefine WITH_FFMPEG #cmakedefine WITH_DSP_EXPERIMENTAL #cmakedefine WITH_DSP_FFMPEG -#cmakedefine WITH_X264 #cmakedefine WITH_OPENCL #cmakedefine WITH_MEDIA_FOUNDATION +#cmakedefine WITH_MEDIACODEC #cmakedefine WITH_VAAPI @@ -74,6 +75,9 @@ #cmakedefine WITH_RDPDR /* Channels */ +#cmakedefine CHANNEL_AINPUT +#cmakedefine CHANNEL_AINPUT_CLIENT +#cmakedefine CHANNEL_AINPUT_SERVER #cmakedefine CHANNEL_AUDIN #cmakedefine CHANNEL_AUDIN_CLIENT #cmakedefine CHANNEL_AUDIN_SERVER diff --git a/docs/README.android b/docs/README.android deleted file mode 100644 index f2da658..0000000 --- a/docs/README.android +++ /dev/null @@ -1,86 +0,0 @@ -Overview -======== - -The FreeRDP Android port consists of three parts: -* Android Java GUI (client/Android/Studio) -* FreeRDP library and its dependencies -* JNI bindings (client/Android/android_freerdp.c - and client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java) - -Build requirements -================= - -For the Android port some additional dependencies need to be fulfilled: - -* for JNI -- CMake >= 3.0 -- Android NDK (>= r9) - -* for the Java GUI -- Android SDK - -FreeRDP requires openssl libraries for building but they are not part of the -Android NDK and therefore they need to be prebuild manually. - -For jpeg support https://github.com/akallabeth/jpeg8d has been tested and used. -However, any other static builds should work as well. - -Build native libraries: -====================== -From the project root run the build script -./scripts/android-build-freerdp.sh --ndk --sdk -Set ANDROID_NDK and ANDROID_SDK to the absolute paths on your machine. -This will fetch sources from git and build OpenSSL, OpenH264, libJPEG. -The native FreeRDP libraries will also be build. - -Currently the default script builds for: -* armeabi -* armeabi-v7a -* x86 -* mips -* arm64-v8a -* x86_64 -* mips64 - -When the script is finished the libraries are ready for android studio to -be picked up in client/Android/Studio/freeRDPCore/src/main/jniLibs - -The default configuration build configuration can be found in -./scripts/android-build.conf and is configured to provide debug builds. -They are limited to API level 21 and above. - -If release binaries (and old android API support) are required, build 32 bit architectures with -./scripts/android-build-freerdp.sh --ndk --sdk --conf ./scripts/android-build-32.conf -and 64 bit architectures with -./scripts/android-build-freerdp.sh --ndk --sdk --conf ./scripts/android-build-64.conf - -Building the APK (Android Studio) -================ - -* Import the folder client/Android/Studio in Android Studio -* You are ready to go - -Building the APK (gradle) -================ - -* change to directory client/Android/Studio -* run ./gradlew build to build -* run ./gradlew tasks for other gradle options - -Development -=========== - -Updating JNI ------------- - -Whenever the FreeRDP API changes or you need some extra functionality in your Java -GUI the JNI needs to be updated. - -The JNI functions are defined in client/Android/android_freerdp.c -Add the new functions to the methods struct. - -* edit client/Android/src/com/freerdp/afreerdp/services/LibFreeRDP.Java to - reflect your changes -* edit client/Android/android_freerdp.c and adjust the methods struct to reflect - the changes made. - diff --git a/docs/README.ios b/docs/README.ios deleted file mode 100644 index c4f767e..0000000 --- a/docs/README.ios +++ /dev/null @@ -1,100 +0,0 @@ -Overview -======== - -The FreeRDP iOS port allows users to enjoy FreeRDP features on Apple iOS devices. -The application was written to be compatible with devices running iOS 4.3 or higher. - -Build requirements -================== - -The following prerequisites are required in order to build the iOS port: - -- cmake version >= 2.8.9 -- latest Xcode installed (>= 4.6) -- installed Provisioning Profile and iOS Developer Certificate for code signing - (not required for simulator builds) -- pre-build static OpenSSL libraries (see below) - -FreeRDP requires OpenSSL libraries for building but they are not part of the iOS SDK and therefore they need to be pre-build manually. -There are various versions and builds of static OpenSSL libraries floating around like iOSPorts. -At the time of writing we have tested and used a small script (OpenSSL-DownloadAndBuild.command) that downloads and builds armv7, armv7s and i386 versions of the OpenSSL 1.0.0e libraries. - -If you don't care about modifying the OpenSSL build you can run the following command in the FreeRDP root directory: - -./scripts/OpenSSL-DownloadAndBuild.command - -The output of the script will be found in external/openssl/. In case you want a -different install/build directory you specify it as first parameter: - -./scripts/OpenSSL-DownloadAndBuild.command /tmp/ - -In the example above the output can then be found in /tmp/openssl. - -The script uses oldest iOS/iPhoneSimulator SDK found on the build machine per default. If it is required to build against a specific SDK version -the variable SDK_VERSION can be used to specify it. The minimum SDK version that should be used can be set with MIN_SDK_VERSION within the script. - -When the script is finished you will find libcrypto.a and libssl.at, both universal libraries containing all openssl/lib -subfolder in the specified -install directory (external per default) - -When the script finishes you will find libcrypto.a and libssl.a, both universal -binary libraries containing arm and i386 targets in order to compile FreeRDP for -iOS devices and the simulator, in the lib subfolder of your installation -directory. - -If you build OpenSSL youself or with an install directory specified you need to set FREERDP_IOS_EXTERNAL_SSL_PATH when running cmake. - - -Building -======== - -Run the following commands in the top level FreeRDP directory: - -cmake -DCMAKE_TOOLCHAIN_FILE=cmake/iOSToolchain.cmake -GXcode - -This command will create a XCode project in the FreeRDP root folder called FreeRDP.xcodeproj. -Open the project in XCode and modify, build or run the app. - -Alternatively you can also build the project from the command line using xcodebuild: - -xcodebuild -project FreeRDP.xcodeproj -configuration Debug -sdk iphoneos6.1 - -or with cmake --build . in your build directory. - -Notes: - -* XCode, by default will build the application into its derived data location (usually in ~/Library/Developer/...). -If you want to specify an output directory add CONFIGURATION_BUILD_DIR= to the end of above command line. - -* If using XCode choose "Open Other" from the welcome screen, browse to the FreeRDP root directory and select FreeRDP.xcodeproj. Alternatively you can - also start it with "open FreeRDP.xcodeproj". - -* If you switch between platforms (OS and SIMULATOR) please remove CMakeCache.txt and CMakeFiles/ before calling cmake again. - Otherwise build errors might occur (this seems to be a bug with cmake or the cmake scripts). To switch between platforms do: - - rm CMakeCache.txt - rm -rf CMakeFiles/ - - before you run a new cmake command with the desired platform. - - -cmake variables -=============== - -CMAKE_TOOLCHAIN_FILE -* the toolchain file to use must be cmake/iOSToolchain.cmake - -IOS_PLATFORM (OS (default), SIMULATOR) -* the platform for which to build iFreeRDP. OS compiles for iOS devices (using armv7 and armv7s ABIs) and SIMULATOR compiles for the iOS Simulator (i386) - -CMAKE_IOS_DEVELOPER_ROOT (used by toolchain file) -* absolute path to the iOS developer platform (i.e. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer) the toolchain file will usually auto-detect the correct Developer platform depending on IOS_PLATFORM - -CMAKE_IOS_SDK_ROOT (used by toolchain file) -* absolute path to the iOS SDK (i.e. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk) the toolchain file will usually auto-detect the correct SDK, depending on IOS_PLATFORM - -FREERDP_IOS_EXTERNAL_SSL_PATH (used by FindOpenSSL) -* absolut root path to the pre-built static OpenSSL libraries - -CODE_SIGN_IDENTITY -* specify the identity to sign the code with diff --git a/docs/README.macOS b/docs/README.macOS deleted file mode 100644 index d9fbb6b..0000000 --- a/docs/README.macOS +++ /dev/null @@ -1,7 +0,0 @@ -Starting with "El Capitan" Apple removed the openssl headers. Therefore it's -required to build openssl manually upfront. For example by using MacPorts or Homebrew. -To build FreeRDP against this library it's required to set the PKG_CONFIG_PATH -pointing to the openssl root directory befor building. -For example with brew it would look like this: - -export PKG_CONFIG_PATH=$(brew --prefix)/opt/openssl/lib/pkgconfig diff --git a/include/freerdp/channels/ainput.h b/include/freerdp/channels/ainput.h new file mode 100644 index 0000000..fe9faef --- /dev/null +++ b/include/freerdp/channels/ainput.h @@ -0,0 +1,61 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_AINPUT_H +#define FREERDP_CHANNEL_AINPUT_H + +#include +#include +#include + +#define AINPUT_CHANNEL_NAME "ainput" +#define AINPUT_DVC_CHANNEL_NAME "FreeRDP::Advanced::Input" + +typedef enum +{ + MSG_AINPUT_VERSION = 0x01, + MSG_AINPUT_MOUSE = 0x02 +} eAInputMsgType; + +typedef enum +{ + AINPUT_FLAGS_WHEEL = 0x0001, + AINPUT_FLAGS_MOVE = 0x0004, + AINPUT_FLAGS_DOWN = 0x0008, + + AINPUT_FLAGS_REL = 0x0010, + AINPUT_FLAGS_HAVE_REL = 0x0020, + + /* Pointer Flags */ + AINPUT_FLAGS_BUTTON1 = 0x1000, /* left */ + AINPUT_FLAGS_BUTTON2 = 0x2000, /* right */ + AINPUT_FLAGS_BUTTON3 = 0x4000, /* middle */ + + /* Extended Pointer Flags */ + AINPUT_XFLAGS_BUTTON1 = 0x0100, + AINPUT_XFLAGS_BUTTON2 = 0x0200 +} AInputEventFlags; + +typedef struct ainput_client_context AInputClientContext; + +#define AINPUT_VERSION_MAJOR 1 +#define AINPUT_VERSION_MINOR 0 + +#endif /* FREERDP_CHANNEL_AINPUT_H */ diff --git a/include/freerdp/client/ainput.h b/include/freerdp/client/ainput.h new file mode 100644 index 0000000..1447483 --- /dev/null +++ b/include/freerdp/client/ainput.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Display Update Virtual Channel Extension + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * + * 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_AINPUT_CLIENT_AINPUT_H +#define FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H + +#include + +typedef UINT (*pcAInputSendInputEvent)(AInputClientContext* context, UINT64 flags, INT32 x, + INT32 y); + +struct ainput_client_context +{ + void* handle; + void* custom; + + pcAInputSendInputEvent AInputSendInputEvent; +}; + +#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H */ diff --git a/include/freerdp/server/ainput.h b/include/freerdp/server/ainput.h new file mode 100644 index 0000000..39acad1 --- /dev/null +++ b/include/freerdp/server/ainput.h @@ -0,0 +1,114 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * AInput Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_AINPUT_SERVER_H +#define FREERDP_CHANNEL_AINPUT_SERVER_H + +#include + +typedef enum AINPUT_SERVER_OPEN_RESULT +{ + AINPUT_SERVER_OPEN_RESULT_OK = 0, + AINPUT_SERVER_OPEN_RESULT_CLOSED = 1, + AINPUT_SERVER_OPEN_RESULT_NOTSUPPORTED = 2, + AINPUT_SERVER_OPEN_RESULT_ERROR = 3 +} AINPUT_SERVER_OPEN_RESULT; + +typedef struct _ainput_server_context ainput_server_context; + +typedef UINT (*psAInputServerInitialize)(ainput_server_context* context, BOOL externalThread); +typedef UINT (*psAInputServerPoll)(ainput_server_context* context); +typedef BOOL (*psAInputServerChannelHandle)(ainput_server_context* context, HANDLE* handle); + +typedef UINT (*psAInputServerOpen)(ainput_server_context* context); +typedef UINT (*psAInputServerClose)(ainput_server_context* context); +typedef BOOL (*psAInputServerIsOpen)(ainput_server_context* context); + +typedef UINT (*psAInputServerOpenResult)(ainput_server_context* context, + AINPUT_SERVER_OPEN_RESULT result); +typedef UINT (*psAInputServerMouseEvent)(ainput_server_context* context, UINT64 timestamp, + UINT64 flags, INT32 x, INT32 y); + +struct _ainput_server_context +{ + HANDLE vcm; + + /* Server self-defined pointer. */ + void* data; + + /*** APIs called by the server. ***/ + /** + * Open the ainput channel. + */ + psAInputServerOpen Open; + + /** + * Optional: Set thread handling. + * When externalThread=TRUE the application is responsible to call + * ainput_server_context_poll periodically to process input events. + * + * Defaults to externalThread=FALSE + */ + psAInputServerInitialize Initialize; + + /** + * @brief Poll When externalThread=TRUE call periodically from your main loop. + * if externalThread=FALSE do not call. + */ + psAInputServerPoll Poll; + + /** + * @brief Poll When externalThread=TRUE call to get a handle to wait for events. + * Will return FALSE until the handle is available. + */ + psAInputServerChannelHandle ChannelHandle; + + /** + * Close the ainput channel. + */ + psAInputServerClose Close; + /** + * Status of the ainput channel. + */ + psAInputServerIsOpen IsOpen; + + /*** Callbacks registered by the server. ***/ + + /** + * Receive ainput mouse event PDU. + */ + psAInputServerMouseEvent MouseEvent; + + rdpContext* rdpcontext; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API ainput_server_context* ainput_server_context_new(HANDLE vcm); + FREERDP_API void ainput_server_context_free(ainput_server_context* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_AINPUT_SERVER_H */ diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index e3a4103..5b74614 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -220,12 +220,6 @@ if(WITH_JPEG) freerdp_library_add(${JPEG_LIBRARIES}) endif() -if(WITH_X264) - set(CODEC_SRCS ${CODEC_SRCS} codec/h264_x264.c) - freerdp_include_directory_add(${X264_INCLUDE_DIR}) - freerdp_library_add(${X264_LIBRARIES}) -endif() - if(WITH_OPENH264) set(CODEC_SRCS ${CODEC_SRCS} codec/h264_openh264.c) freerdp_include_directory_add(${OPENH264_INCLUDE_DIR}) @@ -244,6 +238,10 @@ if(WIN32 AND WITH_MEDIA_FOUNDATION) set(CODEC_SRCS ${CODEC_SRCS} codec/h264_mf.c) endif() +if(ANDROID AND WITH_MEDIACODEC) + list(APPEND CODEC_SRCS codec/h264_mediacodec.c) +endif() + freerdp_module_add(${CODEC_SRCS}) if(BUILD_TESTING) diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c index 0af3cf4..086c797 100644 --- a/libfreerdp/codec/dsp_ffmpeg.c +++ b/libfreerdp/codec/dsp_ffmpeg.c @@ -571,7 +571,9 @@ BOOL freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* format, BOOL encode) FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode) { FREERDP_DSP_CONTEXT* context; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100) avcodec_register_all(); +#endif context = calloc(1, sizeof(FREERDP_DSP_CONTEXT)); if (!context) @@ -667,7 +669,9 @@ BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* if (!context || !srcFormat || !data || !out || context->encoder) return FALSE; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100) av_init_packet(context->packet); +#endif context->packet->data = (uint8_t*)data; context->packet->size = length; return ffmpeg_decode(context->context, context->packet, context->frame, context->rcontext, diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index 00b812b..36b5a7c 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -484,7 +484,7 @@ INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, RECTANGLE_16* regionRects, #define MAX_SUBSYSTEMS 10 static INIT_ONCE subsystems_once = INIT_ONCE_STATIC_INIT; -static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS]; +static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS] = { 0 }; #if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION) extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF; @@ -493,7 +493,14 @@ extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF; static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOID* context) { int i = 0; - ZeroMemory(subSystems, sizeof(subSystems)); + +#ifdef WITH_MEDIACODEC + { + extern H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec; + subSystems[i] = &g_Subsystem_mediacodec; + i++; + } +#endif #if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION) { subSystems[i] = &g_Subsystem_MF; @@ -513,13 +520,6 @@ static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOI subSystems[i] = &g_Subsystem_libavcodec; i++; } -#endif -#ifdef WITH_X264 - { - extern H264_CONTEXT_SUBSYSTEM g_Subsystem_x264; - subSystems[i] = &g_Subsystem_x264; - i++; - } #endif return i > 0; } diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c new file mode 100644 index 0000000..ba207e5 --- /dev/null +++ b/libfreerdp/codec/h264_mediacodec.c @@ -0,0 +1,649 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * H.264 Bitmap Compression + * + * Copyright 2022 Ely Ronnen + * + * 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. + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include "h264.h" + +#define WINPR_ASSERT(x) assert(x) + +#define RESOLVE_MEDIANDK_FUNC(sys, name) \ + ({ \ + BOOL rc = TRUE; \ + sys->fn##name = GetProcAddress(sys->mediandkLibrary, #name); \ + if (sys->fn##name == NULL) \ + { \ + WLog_Print(h264->log, WLOG_ERROR, \ + "Error resolving function " #name " from libmediandk.so"); \ + rc = FALSE; \ + } \ + rc; \ + }) + +#define RESOLVE_MEDIANDK_VARIABLE(sys, member, exported) \ + ({ \ + BOOL rc = FALSE; \ + const char** temp = GetProcAddress(sys->mediandkLibrary, exported); \ + if (temp == NULL) \ + { \ + WLog_Print(h264->log, WLOG_ERROR, \ + "Error resolving variable " exported " from libmediandk.so"); \ + } \ + else \ + { \ + sys->member = *temp; \ + rc = TRUE; \ + } \ + rc; \ + }) + +typedef AMediaFormat* (*AMediaFormat_new_t)(void); +typedef media_status_t (*AMediaFormat_delete_t)(AMediaFormat*); +typedef const char* (*AMediaFormat_toString_t)(AMediaFormat*); +typedef void (*AMediaFormat_setInt32_t)(AMediaFormat*, const char*, int32_t); +typedef void (*AMediaFormat_setString_t)(AMediaFormat*, const char*, const char*); +typedef AMediaCodec* (*AMediaCodec_createDecoderByType_t)(const char*); +typedef media_status_t (*AMediaCodec_delete_t)(AMediaCodec*); +typedef media_status_t (*AMediaCodec_configure_t)(AMediaCodec*, const AMediaFormat*, ANativeWindow*, + AMediaCrypto*, uint32_t); +typedef media_status_t (*AMediaCodec_start_t)(AMediaCodec*); +typedef media_status_t (*AMediaCodec_stop_t)(AMediaCodec*); +typedef uint8_t* (*AMediaCodec_getInputBuffer_t)(AMediaCodec*, size_t, size_t*); +typedef uint8_t* (*AMediaCodec_getOutputBuffer_t)(AMediaCodec*, size_t, size_t*); +typedef ssize_t (*AMediaCodec_dequeueInputBuffer_t)(AMediaCodec*, int64_t); +typedef media_status_t (*AMediaCodec_queueInputBuffer_t)(AMediaCodec*, size_t, ssize_t, size_t, + uint64_t, uint32_t); +typedef ssize_t (*AMediaCodec_dequeueOutputBuffer_t)(AMediaCodec*, AMediaCodecBufferInfo*, int64_t); +typedef AMediaFormat* (*AMediaCodec_getOutputFormat_t)(AMediaCodec*); +typedef media_status_t (*AMediaCodec_releaseOutputBuffer_t)(AMediaCodec*, size_t, bool); +typedef media_status_t (*AMediaCodec_setParameters_t)(AMediaCodec*, const AMediaFormat*); // 26 +typedef media_status_t (*AMediaCodec_getName_t)(AMediaCodec*, char**); // 28 +typedef void (*AMediaCodec_releaseName_t)(AMediaCodec*, char*); // 28 +typedef AMediaFormat* (*AMediaCodec_getInputFormat_t)(AMediaCodec*); // 28 + +const int COLOR_FormatYUV420Planar = 19; +const int COLOR_FormatYUV420Flexible = 0x7f420888; + +struct _H264_CONTEXT_MEDIACODEC +{ + AMediaCodec* decoder; + AMediaFormat* inputFormat; + AMediaFormat* outputFormat; + int32_t width; + int32_t height; + ssize_t currentOutputBufferIndex; + + // libmediandk.so imports + HMODULE mediandkLibrary; + + AMediaFormat_new_t fnAMediaFormat_new; + AMediaFormat_delete_t fnAMediaFormat_delete; + AMediaFormat_toString_t fnAMediaFormat_toString; + AMediaFormat_setInt32_t fnAMediaFormat_setInt32; + AMediaFormat_setString_t fnAMediaFormat_setString; + AMediaCodec_createDecoderByType_t fnAMediaCodec_createDecoderByType; + AMediaCodec_delete_t fnAMediaCodec_delete; + AMediaCodec_configure_t fnAMediaCodec_configure; + AMediaCodec_start_t fnAMediaCodec_start; + AMediaCodec_stop_t fnAMediaCodec_stop; + AMediaCodec_getInputBuffer_t fnAMediaCodec_getInputBuffer; + AMediaCodec_getOutputBuffer_t fnAMediaCodec_getOutputBuffer; + AMediaCodec_dequeueInputBuffer_t fnAMediaCodec_dequeueInputBuffer; + AMediaCodec_queueInputBuffer_t fnAMediaCodec_queueInputBuffer; + AMediaCodec_dequeueOutputBuffer_t fnAMediaCodec_dequeueOutputBuffer; + AMediaCodec_getOutputFormat_t fnAMediaCodec_getOutputFormat; + AMediaCodec_releaseOutputBuffer_t fnAMediaCodec_releaseOutputBuffer; + AMediaCodec_setParameters_t fnAMediaCodec_setParameters; + AMediaCodec_getName_t fnAMediaCodec_getName; + AMediaCodec_releaseName_t fnAMediaCodec_releaseName; + AMediaCodec_getInputFormat_t fnAMediaCodec_getInputFormat; + + const char* gAMediaFormatKeyMime; + const char* gAMediaFormatKeyWidth; + const char* gAMediaFormatKeyHeight; + const char* gAMediaFormatKeyColorFormat; +}; + +typedef struct _H264_CONTEXT_MEDIACODEC H264_CONTEXT_MEDIACODEC; + +static int load_libmediandk(H264_CONTEXT* h264) +{ + BOOL rc; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec Loading libmediandk.so"); + + sys->mediandkLibrary = LoadLibraryA("libmediandk.so"); + if (sys->mediandkLibrary == NULL) + { + WLog_Print(h264->log, WLOG_WARN, "Error loading libmediandk.so"); + return -1; + } + + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_new); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_delete); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_toString); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setInt32); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setString); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_createDecoderByType); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_delete); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_configure); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_start); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_stop); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueInputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_queueInputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueOutputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputFormat); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseOutputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_setParameters); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getName); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseName); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputFormat); + if (!rc) + return -1; + + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyMime, "AMEDIAFORMAT_KEY_MIME"); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyWidth, "AMEDIAFORMAT_KEY_WIDTH"); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyHeight, "AMEDIAFORMAT_KEY_HEIGHT"); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyColorFormat, + "AMEDIAFORMAT_KEY_COLOR_FORMAT"); + if (!rc) + return -1; + + return 0; +} + +static void unload_libmediandk(H264_CONTEXT* h264) +{ + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + if (NULL == sys->mediandkLibrary) + { + return; + } + + FreeLibrary(sys->mediandkLibrary); +} + +static void set_mediacodec_format(H264_CONTEXT* h264, AMediaFormat** formatVariable, + AMediaFormat* newFormat) +{ + media_status_t status = AMEDIA_OK; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + WINPR_ASSERT(formatVariable); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + if (*formatVariable != NULL) + { + status = sys->fnAMediaFormat_delete(*formatVariable); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaFormat_delete %d", status); + } + } + + *formatVariable = newFormat; +} + +static void release_current_outputbuffer(H264_CONTEXT* h264) +{ + media_status_t status = AMEDIA_OK; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + if (sys->currentOutputBufferIndex < 0) + { + return; + } + + status = + sys->fnAMediaCodec_releaseOutputBuffer(sys->decoder, sys->currentOutputBufferIndex, FALSE); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_releaseOutputBuffer %d", status); + } + + sys->currentOutputBufferIndex = -1; +} + +static int mediacodec_compress(H264_CONTEXT* h264, const BYTE** pSrcYuv, const UINT32* pStride, + BYTE** ppDstData, UINT32* pDstSize) +{ + WINPR_ASSERT(h264); + WINPR_ASSERT(pSrcYuv); + WINPR_ASSERT(pStride); + WINPR_ASSERT(ppDstData); + WINPR_ASSERT(pDstSize); + + WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); + return -1; +} + +static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize) +{ + ssize_t inputBufferId = -1; + size_t inputBufferSize, outputBufferSize; + uint8_t* inputBuffer; + media_status_t status; + const char* media_format; + BYTE** pYUVData; + UINT32* iStride; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + WINPR_ASSERT(pSrcData); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + pYUVData = h264->pYUVData; + WINPR_ASSERT(pYUVData); + + iStride = h264->iStride; + WINPR_ASSERT(iStride); + + release_current_outputbuffer(h264); + + if (sys->width == 0) + { + int32_t width = h264->width; + int32_t height = h264->height; + if (width % 16 != 0) + width += 16 - width % 16; + if (height % 16 != 0) + height += 16 - height % 16; + + WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec setting width and height [%d,%d]", width, + height); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, width); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, height); + + status = sys->fnAMediaCodec_setParameters(sys->decoder, sys->inputFormat); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_setParameters failed: %d", status); + return -1; + } + + sys->width = width; + sys->height = height; + } + + while (true) + { + UINT32 inputBufferCurrnetOffset = 0; + while (inputBufferCurrnetOffset < SrcSize) + { + UINT32 numberOfBytesToCopy = SrcSize - inputBufferCurrnetOffset; + inputBufferId = sys->fnAMediaCodec_dequeueInputBuffer(sys->decoder, -1); + if (inputBufferId < 0) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]", + inputBufferId); + // TODO: sleep? + continue; + } + + inputBuffer = + sys->fnAMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize); + if (inputBuffer == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed"); + return -1; + } + + if (numberOfBytesToCopy > inputBufferSize) + { + WLog_Print(h264->log, WLOG_WARN, + "MediaCodec inputBufferSize: got [%d] but wanted [%d]", inputBufferSize, + numberOfBytesToCopy); + numberOfBytesToCopy = inputBufferSize; + } + + memcpy(inputBuffer, pSrcData + inputBufferCurrnetOffset, numberOfBytesToCopy); + inputBufferCurrnetOffset += numberOfBytesToCopy; + + status = sys->fnAMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0, + numberOfBytesToCopy, 0, 0); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status); + return -1; + } + } + + while (true) + { + AMediaCodecBufferInfo bufferInfo; + ssize_t outputBufferId = + sys->fnAMediaCodec_dequeueOutputBuffer(sys->decoder, &bufferInfo, -1); + if (outputBufferId >= 0) + { + sys->currentOutputBufferIndex = outputBufferId; + + uint8_t* outputBuffer; + outputBuffer = sys->fnAMediaCodec_getOutputBuffer(sys->decoder, outputBufferId, + &outputBufferSize); + sys->currentOutputBufferIndex = outputBufferId; + + if (outputBufferSize != (sys->width * sys->height + + ((sys->width + 1) / 2) * ((sys->height + 1) / 2) * 2)) + { + WLog_Print(h264->log, WLOG_ERROR, "Error unexpected output buffer size %d", + outputBufferSize); + return -1; + } + + // TODO: work with AImageReader and get AImage object instead of + // COLOR_FormatYUV420Planar buffer. + iStride[0] = sys->width; + iStride[1] = (sys->width + 1) / 2; + iStride[2] = (sys->width + 1) / 2; + pYUVData[0] = outputBuffer; + pYUVData[1] = outputBuffer + iStride[0] * sys->height; + pYUVData[2] = + outputBuffer + iStride[0] * sys->height + iStride[1] * ((sys->height + 1) / 2); + break; + } + else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) + { + AMediaFormat* outputFormat; + outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); + if (outputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); + return -1; + } + set_mediacodec_format(h264, &sys->outputFormat, outputFormat); + + media_format = sys->fnAMediaFormat_toString(sys->outputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + return -1; + } + } + else if (outputBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) + { + WLog_Print(h264->log, WLOG_WARN, + "AMediaCodec_dequeueOutputBuffer need to try again later"); + // TODO: sleep? + } + else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) + { + WLog_Print(h264->log, WLOG_WARN, + "AMediaCodec_dequeueOutputBuffer returned deprecated value " + "AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED, ignoring"); + } + else + { + WLog_Print(h264->log, WLOG_ERROR, + "AMediaCodec_dequeueOutputBuffer returned unknown value [%d]", + outputBufferId); + return -1; + } + } + + break; + } + + return 1; +} + +static void mediacodec_uninit(H264_CONTEXT* h264) +{ + media_status_t status = AMEDIA_OK; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + + WLog_Print(h264->log, WLOG_DEBUG, "Uninitializing MediaCodec"); + + if (!sys) + return; + + if (sys->decoder != NULL) + { + release_current_outputbuffer(h264); + status = sys->fnAMediaCodec_stop(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_stop %d", status); + } + + status = sys->fnAMediaCodec_delete(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_delete %d", status); + } + + sys->decoder = NULL; + } + + set_mediacodec_format(h264, &sys->inputFormat, NULL); + set_mediacodec_format(h264, &sys->outputFormat, NULL); + + unload_libmediandk(h264); + + free(sys); + h264->pSystemData = NULL; +} + +static BOOL mediacodec_init(H264_CONTEXT* h264) +{ + H264_CONTEXT_MEDIACODEC* sys; + media_status_t status; + const char* media_format; + char* codec_name; + AMediaFormat *inputFormat, *outputFormat; + + WINPR_ASSERT(h264); + + if (h264->Compressor) + { + WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); + goto EXCEPTION; + } + + WLog_Print(h264->log, WLOG_DEBUG, "Initializing MediaCodec"); + + sys = (H264_CONTEXT_MEDIACODEC*)calloc(1, sizeof(H264_CONTEXT_MEDIACODEC)); + + if (!sys) + { + goto EXCEPTION; + } + + h264->pSystemData = (void*)sys; + + if (load_libmediandk(h264) < 0) + { + goto EXCEPTION; + } + + sys->currentOutputBufferIndex = -1; + sys->width = sys->height = 0; // update when we're given the height and width + sys->decoder = sys->fnAMediaCodec_createDecoderByType("video/avc"); + if (sys->decoder == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_createCodecByName failed"); + goto EXCEPTION; + } + + status = sys->fnAMediaCodec_getName(sys->decoder, &codec_name); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getName failed: %d", status); + goto EXCEPTION; + } + + WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec using video/avc codec [%s]", codec_name); + sys->fnAMediaCodec_releaseName(sys->decoder, codec_name); + + sys->inputFormat = sys->fnAMediaFormat_new(); + if (sys->inputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_new failed"); + goto EXCEPTION; + } + + sys->fnAMediaFormat_setString(sys->inputFormat, sys->gAMediaFormatKeyMime, "video/avc"); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, sys->width); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, sys->height); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyColorFormat, + COLOR_FormatYUV420Planar); + + media_format = sys->fnAMediaFormat_toString(sys->inputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + + status = sys->fnAMediaCodec_configure(sys->decoder, sys->inputFormat, NULL, NULL, 0); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_configure failed: %d", status); + goto EXCEPTION; + } + + inputFormat = sys->fnAMediaCodec_getInputFormat(sys->decoder); + if (inputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputFormat failed"); + goto EXCEPTION; + } + set_mediacodec_format(h264, &sys->inputFormat, inputFormat); + + media_format = sys->fnAMediaFormat_toString(sys->inputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with input MediaFormat [%s]", media_format); + + outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); + if (outputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); + goto EXCEPTION; + } + set_mediacodec_format(h264, &sys->outputFormat, outputFormat); + + media_format = sys->fnAMediaFormat_toString(sys->outputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with output MediaFormat [%s]", + media_format); + + WLog_Print(h264->log, WLOG_DEBUG, "Starting MediaCodec"); + status = sys->fnAMediaCodec_start(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_start failed %d", status); + goto EXCEPTION; + } + + return TRUE; +EXCEPTION: + mediacodec_uninit(h264); + return FALSE; +} + +H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec = { "MediaCodec", mediacodec_init, mediacodec_uninit, + mediacodec_decompress, mediacodec_compress }; diff --git a/libfreerdp/codec/h264_x264.c b/libfreerdp/codec/h264_x264.c deleted file mode 100644 index c360094..0000000 --- a/libfreerdp/codec/h264_x264.c +++ /dev/null @@ -1,117 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * H.264 Bitmap Compression - * - * Copyright 2015 Marc-André 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 NAL_UNKNOWN X264_NAL_UNKNOWN -#define NAL_SLICE X264_NAL_SLICE -#define NAL_SLICE_DPA X264_NAL_SLICE_DPA -#define NAL_SLICE_DPB X264_NAL_SLICE_DPB -#define NAL_SLICE_DPC X264_NAL_SLICE_DPC -#define NAL_SLICE_IDR X264_NAL_SLICE_IDR -#define NAL_SEI X264_NAL_SEI -#define NAL_SPS X264_NAL_SPS -#define NAL_PPS X264_NAL_PPS -#define NAL_AUD X264_NAL_AUD -#define NAL_FILLER X264_NAL_FILLER - -#define NAL_PRIORITY_DISPOSABLE X264_NAL_PRIORITY_DISPOSABLE -#define NAL_PRIORITY_LOW X264_NAL_PRIORITY_LOW -#define NAL_PRIORITY_HIGH X264_NAL_PRIORITY_HIGH -#define NAL_PRIORITY_HIGHEST X264_NAL_PRIORITY_HIGHEST - -#include -#include -#include - -#error "X264 backend not implemented, please review your configuration!" - -struct _H264_CONTEXT_X264 -{ - void* dummy; -}; -typedef struct _H264_CONTEXT_X264 H264_CONTEXT_X264; - -static int x264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) -{ - // H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData; - return -1; -} - -static int x264_compress(H264_CONTEXT* h264, const BYTE** ppSrcYuv, const UINT32* pStride, - BYTE** ppDstData, UINT32* pDstSize) -{ - // H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData; - return -1; -} - -static void x264_uninit(H264_CONTEXT* h264) -{ - H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*)h264->pSystemData; - - if (sys) - { - free(sys); - h264->pSystemData = NULL; - } -} - -static BOOL x264_init(H264_CONTEXT* h264) -{ - H264_CONTEXT_X264* sys; - h264->numSystemData = 1; - sys = (H264_CONTEXT_X264*)calloc(h264->numSystemData, sizeof(H264_CONTEXT_X264)); - - if (!sys) - { - goto EXCEPTION; - } - - h264->pSystemData = (void*)sys; - - if (h264->Compressor) - { - } - else - { - } - - return TRUE; -EXCEPTION: - x264_uninit(h264); - return FALSE; -} - -H264_CONTEXT_SUBSYSTEM g_Subsystem_x264 = { "x264", x264_init, x264_uninit, x264_decompress, - x264_compress }; - -#undef NAL_UNKNOWN -#undef NAL_SLICE -#undef NAL_SLICE_DPA -#undef NAL_SLICE_DPB -#undef NAL_SLICE_DPC -#undef NAL_SLICE_IDR -#undef NAL_SEI -#undef NAL_SPS -#undef NAL_PPS -#undef NAL_AUD -#undef NAL_FILLER - -#undef NAL_PRIORITY_DISPOSABLE -#undef NAL_PRIORITY_LOW -#undef NAL_PRIORITY_HIGH -#undef NAL_PRIORITY_HIGHEST diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 08b8199..60343b8 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -23,6 +23,7 @@ #include "config.h" #endif +#include #include #include #include @@ -40,6 +41,8 @@ #include "rfx_types.h" #include "progressive.h" +#define WINPR_ASSERT(x) assert(x) + #define TAG FREERDP_TAG("codec.progressive") struct _RFX_PROGRESSIVE_UPGRADE_STATE @@ -434,6 +437,36 @@ static INLINE BOOL progressive_tile_allocate(RFX_PROGRESSIVE_TILE* tile) return rc; } +static BOOL progressive_allocate_tile_cache(PROGRESSIVE_SURFACE_CONTEXT* surface) +{ + size_t oldIndex; + + WINPR_ASSERT(surface); + WINPR_ASSERT(surface->gridSize > 0); + + oldIndex = surface->gridSize; + if (surface->tiles) + surface->gridSize *= 2; + + { + void* tmp = realloc(surface->tiles, surface->gridSize * sizeof(RFX_PROGRESSIVE_TILE)); + if (!tmp) + return FALSE; + surface->tiles = tmp; + memset(&surface->tiles[oldIndex], 0, + (surface->gridSize - oldIndex) * sizeof(RFX_PROGRESSIVE_TILE)); + } + { + void* tmp = realloc(surface->updatedTileIndices, surface->gridSize * sizeof(UINT32)); + if (!tmp) + return FALSE; + surface->updatedTileIndices = tmp; + memset(&surface->updatedTileIndices[oldIndex], 0, + (surface->gridSize - oldIndex) * sizeof(UINT32)); + } + return TRUE; +} + static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfaceId, UINT32 width, UINT32 height) { @@ -450,14 +483,10 @@ static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfa surface->gridWidth = (width + (64 - width % 64)) / 64; surface->gridHeight = (height + (64 - height % 64)) / 64; surface->gridSize = surface->gridWidth * surface->gridHeight; - surface->tiles = (RFX_PROGRESSIVE_TILE*)calloc(surface->gridSize, sizeof(RFX_PROGRESSIVE_TILE)); - surface->updatedTileIndices = (UINT32*)calloc(surface->gridSize, sizeof(UINT32)); - if (!surface->tiles || !surface->updatedTileIndices) + if (!progressive_allocate_tile_cache(surface)) { - free(surface->updatedTileIndices); - free(surface->tiles); - free(surface); + progressive_surface_context_free(surface); return NULL; } for (x = 0; x < surface->gridSize; x++) @@ -549,8 +578,8 @@ static BOOL progressive_surface_tile_replace(PROGRESSIVE_SURFACE_CONTEXT* surfac } if (surface->numUpdatedTiles >= surface->gridSize) { - WLog_ERR(TAG, "Invalid total tile count, maximum %" PRIu32, surface->gridSize); - return FALSE; + if (!progressive_allocate_tile_cache(surface)) + return FALSE; } region->tiles[region->usedTiles++] = t; diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 2ce9cf7..a070d0c 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -181,7 +181,8 @@ BOOL freerdp_connect(freerdp* instance) if (status) status2 = freerdp_channels_pre_connect(instance->context->channels, instance); - if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) + if (settings->KeyboardLayout == KBD_JAPANESE || + settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) { settings->KeyboardType = 7; settings->KeyboardSubType = 2; diff --git a/scripts/android-build-32.conf b/scripts/android-build-32.conf deleted file mode 100644 index 4bafb23..0000000 --- a/scripts/android-build-32.conf +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Android build confguration -# -# Note: This is a simple configuration to build all -# architectures in one rush. -# Since android 64 bit support was introduced with NDK API 21 -# this is the minimal common denominator. -# If you require support for older NDK API levels, -# create seperate configurations for each NDK API level -# and architecture you want to support. -WITH_JPEG=0 -WITH_OPENH264=1 -WITH_OPENSSL=1 -BUILD_DEPS=1 -DEPS_ONLY=0 -NDK_TARGET=21 - -JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1j - -SRC_DIR=$SCRIPT_PATH/.. -BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs -BUILD_SRC=$SRC_DIR/build - -CMAKE_BUILD_TYPE=Release - -BUILD_ARCH="armeabi-v7a x86" diff --git a/scripts/android-build-64.conf b/scripts/android-build-64.conf deleted file mode 100644 index a3dcf71..0000000 --- a/scripts/android-build-64.conf +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Android build confguration -# -# Note: This is a simple configuration to build all -# architectures in one rush. -# Since android 64 bit support was introduced with NDK API 21 -# this is the minimal common denominator. -# If you require support for older NDK API levels, -# create seperate configurations for each NDK API level -# and architecture you want to support. -WITH_JPEG=0 -WITH_OPENH264=1 -WITH_OPENSSL=1 -BUILD_DEPS=1 -DEPS_ONLY=0 -NDK_TARGET=21 - -JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1j - -SRC_DIR=$SCRIPT_PATH/.. -BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs -BUILD_SRC=$SRC_DIR/build - -CMAKE_BUILD_TYPE=Release - -BUILD_ARCH="arm64-v8a x86_64" diff --git a/scripts/android-build-common.sh b/scripts/android-build-common.sh deleted file mode 100644 index 11fda67..0000000 --- a/scripts/android-build-common.sh +++ /dev/null @@ -1,292 +0,0 @@ -#!/bin/bash - -SCRIPT_PATH=$(dirname "${BASH_SOURCE[0]}") -SCRIPT_PATH=$(realpath "$SCRIPT_PATH") - -if [ -z $BUILD_ARCH ]; then - BUILD_ARCH="armeabi-v7a x86 x86_64 arm64-v8a" -fi - -if [ -z $NDK_TARGET ]; then - NDK_TARGET=21 -fi - -if [ -z $CMAKE_PROGRAM ]; then - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit) -fi - -if [ -z $CCACHE ]; then - CCACHE=$(which ccache) -fi - -if [ -z $ANDROID_NDK ]; then - ANDROID_NDK="missing" -fi - -if [ -z $ANDROID_SDK ]; then - ANDROID_SDK="missing" -fi - -if [ -z $BUILD_DST ]; then - BUILD_DST=$(pwd)/libs -fi - -if [ -z $BUILD_SRC ]; then - BUILD_SRC=$(pwd)/src -fi - -if [ -z $SCM_URL ]; then - SCM_URL="missing" -fi - -if [ -z $SCM_TAG ]; then - SCM_TAG=master -fi - -CLEAN_BUILD_DIR=0 - -function common_help { - echo "$(BASHSOURCE[0]) supports the following arguments:" - echo " --ndk The base directory of your android NDK defa" - echo " ANDROID_NDK=$ANDROID_NDK" - echo " --sdk The base directory of your android SDK defa" - echo " ANDROID_SDK=$ANDROID_SDK" - echo " --arch A list of architectures to build" - echo " BUILD_ARCH=$BUILD_ARCH" - echo " --dst The destination directory for include and library files" - echo " BUILD_DST=$BUILD_DST" - echo " --src The source directory for SCM checkout" - echo " BUILD_SRC=$BUILD_SRC" - echo " --url The SCM source url" - echo " SCM_URL=$SCM_URL" - echo " --tag The SCM branch or tag to check out" - echo " SCM_TAG=$SCM_TAG" - echo " --clean Clean the destination before build" - echo " --help Display this help" - exit 0 -} - -function common_run { - echo "[RUN] $@" - "$@" - RES=$? - if [[ $RES -ne 0 ]]; - then - echo "[ERROR] $@ retured $RES" - exit 1 - fi -} - -function common_parse_arguments { - while [[ $# > 0 ]] - do - key="$1" - case $key in - --conf) - source "$2" - shift - ;; - - --target) - NDK_TARGET="$2" - shift - ;; - - --ndk) - ANDROID_NDK="$2" - shift - ;; - - --sdk) - ANDROID_SDK="$2" - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit) - shift - ;; - - --arch) - BUILD_ARCH="$2" - shift - ;; - - --dst) - BUILD_DST="$2" - shift - ;; - - --src) - BUILD_SRC="$2" - shift - ;; - - --url) - SCM_URL="$2" - shift - ;; - - --tag) - SCM_TAG="$2" - shift - ;; - - --clean) - CLEAN_BUILD_DIR=1 - shift - ;; - - --help) - common_help - shift - ;; - - *) # Unknown - ;; - esac - shift - done -} - -function common_check_requirements { - if [[ ! -d $ANDROID_NDK ]]; - then - echo "export ANDROID_NDK to point to your NDK location." - exit 1 - fi - - if [[ ! -d $ANDROID_SDK ]]; - then - echo "export ANDROID_SDK to point to your SDK location." - exit 1 - fi - if [[ -z $BUILD_DST ]]; - then - echo "Destination directory not valid" - exit 1 - fi - - if [[ -z $BUILD_SRC ]]; - then - echo "Source directory not valid" - exit 1 - fi - - if [[ -z $SCM_URL ]]; - then - echo "Source URL not defined! Define SCM_URL" - exit 1 - fi - - if [[ -z $SCM_TAG ]]; - then - echo "SCM TAG / BRANCH not defined! Define SCM_TAG" - exit 1 - fi - - if [[ -z $NDK_TARGET ]]; - then - echo "Android platform NDK_TARGET not defined" - exit 1 - fi - - if [ -x $ANDROID_NDK/ndk-build ]; then - NDK_BUILD=$ANDROID_NDK/ndk-build - else - echo "ndk-build not found in NDK directory $ANDROID_NDK" - echo "assuming ndk-build is in path..." - NDK_BUILD=ndk-build - fi - - if [ -z $CMAKE_PROGRAM ]; then - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit) - fi - - for CMD in make git $CMAKE_PROGRAM $NDK_BUILD - do - if ! type $CMD >/dev/null; then - echo "Command $CMD not found. Install and add it to the PATH." - exit 1 - fi - done - - if [ "${BUILD_SRC:0:1}" != "/" ]; - then - BUILD_SRC=$(pwd)/$BUILD_SRC - fi - if [ "${BUILD_DST:0:1}" != "/" ]; - then - BUILD_DST=$(pwd)/$BUILD_DST - fi -} - -function common_update { - if [ $# -ne 3 ]; - then - echo "Invalid arguments to update function $@" - exit 1 - fi - SCM_URL=$1 - SCM_TAG=$2 - BUILD_SRC=$3 - - echo "Preparing checkout..." - BASE=$(pwd) - CACHE=$SCRIPT_PATH/../cache - common_run mkdir -p $CACHE - TARFILE="$CACHE/$SCM_TAG.tar.gz" - - - if [[ ! -f "$TARFILE" ]]; - then - common_run wget -O "$TARFILE" "$SCM_URL/archive/$SCM_TAG.tar.gz" - fi - - if [[ -d $BUILD_SRC ]]; - then - common_run rm -rf $BUILD_SRC - fi - common_run mkdir -p $BUILD_SRC - common_run cd $BUILD_SRC - common_run tar zxf "$TARFILE" --strip 1 - common_run cd $BASE - -} - -function common_clean { - if [ $CLEAN_BUILD_DIR -ne 1 ]; - then - return - fi - - if [ $# -ne 1 ]; - then - echo "Invalid arguments to clean function $@" - exit 1 - fi - - echo "Cleaning up $1..." - common_run rm -rf $1 -} - -function common_copy { - if [ $# -ne 2 ]; - then - echo "Invalid arguments to copy function $@" - exit 1 - fi - if [ ! -d $1 ] || [ ! -d $1/include ] || [ ! -d $1/libs ]; - then - echo "Invalid source $1" - exit 1 - fi - if [ -z $2 ]; - then - echo "Invalid destination $2" - exit 1 - fi - - if [ ! -d $2 ]; - then - common_run mkdir -p $2 - fi - common_run cp -L -r $1/include $2 - common_run cp -L -r $1/libs/* $2 -} diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh deleted file mode 100755 index 40f26f2..0000000 --- a/scripts/android-build-freerdp.sh +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/bash - -JPEG_TAG=master -OPENH264_TAG=master -OPENSSL_TAG=master - -WITH_JPEG=0 -WITH_OPENH264=0 -WITH_OPENSSL=0 - -SRC_DIR=$(dirname "${BASH_SOURCE[0]}") -SRC_DIR=$(realpath "$SRC_DIR") -BUILD_SRC=$(pwd) -BUILD_DST=$(pwd) - -CMAKE_BUILD_TYPE=Debug -BUILD_DEPS=0 - -SCRIPT_PATH=$(dirname "${BASH_SOURCE[0]}") -source $SCRIPT_PATH/android-build-common.sh -source $SCRIPT_PATH/android-build.conf - -# Parse arguments. -REMAINING="" -while [[ $# > 0 ]] -do - key="$1" - case $key in - --freerdp-src) - SRC_DIR="$2" - shift - ;; - --jpeg) - WITH_JPEG=1 - shift - ;; - --openh264) - WITH_OPENH264=1 - shift - ;; - --openh264-ndk) - shift - ANDROID_NDK_OPENH264=$1 - shift - ;; - --openssl) - WITH_OPENSSL=1 - shift - ;; - --debug) - CMAKE_BUILD_TYPE=Debug - shift - ;; - --release) - CMAKE_BUILD_TYPE=Release - shift - ;; - --relWithDebug) - CMAKE_BUILD_TYPE=RelWithDebug - shift - ;; - --build-deps) - BUILD_DEPS=1 - shift - ;; - *) - REMAINING="$REMAINING $key" - shift - ;; - esac -done -common_parse_arguments $REMAINING - -# clean up top -if [ -d $BUILD_SRC ]; -then - common_clean $BUILD_SRC -fi - -if [ -d $BUILD_DST ]; -then - common_run mkdir -p $BUILD_DST -fi - -# Prepare the environment -common_run mkdir -p $BUILD_SRC - -CMAKE_CMD_ARGS="-DANDROID_NDK=$ANDROID_NDK \ - -DANDROID_NATIVE_API_LEVEL=android-${NDK_TARGET} \ - -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ - -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \ - -DFREERDP_EXTERNAL_PATH=$BUILD_DST \ - -DCMAKE_MAKE_PROGRAM=make" - -BASE=$(pwd) -for ARCH in $BUILD_ARCH -do - # build dependencies. - if [ $WITH_JPEG -ne 0 ]; - then - if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-jpeg.sh \ - --src $BUILD_SRC/jpeg --dst $BUILD_DST \ - --ndk $ANDROID_NDK \ - --arch $ARCH \ - --target $NDK_TARGET \ - --tag $JPEG_TAG - fi - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_JPEG=ON" - else - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_JPEG=OFF" - fi - if [ $WITH_OPENH264 -ne 0 ]; - then - if [ -z "$ANDROID_NDK_OPENH264" ] - then - echo - echo "Warning: Missing openh264-ndk, using $ANDROID_NDK" >&2 - echo - ANDROID_NDK_OPENH264=$ANDROID_NDK - fi - if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-openh264.sh \ - --src $BUILD_SRC/openh264 --dst $BUILD_DST \ - --sdk "$ANDROID_SDK" \ - --ndk "$ANDROID_NDK_OPENH264" \ - --arch $ARCH \ - --target $NDK_TARGET \ - --tag $OPENH264_TAG - fi - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=ON" - else - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=OFF" - fi - if [ $WITH_OPENSSL -ne 0 ]; - then - if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-openssl.sh \ - --src $BUILD_SRC/openssl --dst $BUILD_DST \ - --sdk "$ANDROID_SDK" \ - --ndk $ANDROID_NDK \ - --arch $ARCH \ - --target $NDK_TARGET \ - --tag $OPENSSL_TAG - fi - fi - - # Build and install the library. - if [ $DEPS_ONLY -eq 0 ]; - then - common_run cd $BASE - common_run mkdir -p $BUILD_SRC/freerdp-build/$ARCH - common_run cd $BUILD_SRC/freerdp-build/$ARCH - common_run export ANDROID_NDK=$ANDROID_NDK - common_run $CMAKE_PROGRAM $CMAKE_CMD_ARGS \ - -DANDROID_ABI=$ARCH \ - -DCMAKE_INSTALL_PREFIX=$BUILD_DST/$ARCH \ - -DCMAKE_INSTALL_LIBDIR=. \ - $SRC_DIR - echo $(pwd) - common_run cmake --build . --target install - fi -done - -echo "Successfully build library for architectures $BUILD_ARCH" diff --git a/scripts/android-build-jpeg.sh b/scripts/android-build-jpeg.sh deleted file mode 100755 index dafcf89..0000000 --- a/scripts/android-build-jpeg.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -SCM_URL=https://github.com/akallabeth/jpeg8d -SCM_TAG=master - -source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh - -function usage { - echo $0 [arguments] - echo "\tThe script checks out the OpenH264 git repository" - echo "\tto a local source directory, builds and installs" - echo "\tthe library for all architectures defined to" - echo "\tthe destination directory." - echo "" - echo "\t[-s|--source-dir ]" - echo "\t[-d|--destination-dir ]" - echo "\t[-a|--arch ]" - echo "\t[-t|--tag ]" - echo "\t[--scm-url ]" - echo "\t[--ndk ]" - echo "\t[--sdk ]" - exit 1 -} - -function build { - echo "Building architectures $BUILD_ARCH..." - BASE=$(pwd) - common_run cd $BUILD_SRC - common_run $NDK_BUILD V=1 APP_ABI="${BUILD_ARCH}" NDK_TOOLCHAIN_VERSION=4.9 -j clean - common_run $NDK_BUILD V=1 APP_ABI="${BUILD_ARCH}" NDK_TOOLCHAIN_VERSION=4.9 -j - common_run cd $BASE -} - -# Run the main program. -common_parse_arguments $@ -common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC - -build - -common_copy $BUILD_SRC $BUILD_DST diff --git a/scripts/android-build-openh264.sh b/scripts/android-build-openh264.sh deleted file mode 100755 index 5e9abed..0000000 --- a/scripts/android-build-openh264.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -SCM_URL=https://github.com/cisco/openh264 -SCM_TAG=master - -source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh - -function build { - echo "Building architecture $1..." - BASE=$(pwd) - common_run cd $BUILD_SRC - PATH=$ANDROID_NDK:$PATH - MAKE="make PATH=$PATH ENABLEPIC=Yes OS=android NDKROOT=$ANDROID_NDK TARGET=android-$2 NDKLEVEL=$2 ARCH=$1 -j libraries" - - common_run export QUIET_AR="$CCACHE " - common_run export QUIET_ASM="$CCACHE " - common_run export QUIET_CC="$CCACHE " - common_run export QUIET_CCAR="$CCACHE " - common_run export QUIET_CXX="$CCACHE " - - common_run $MAKE -j - # Install creates a non optimal directory layout, fix that - common_run $MAKE PREFIX=$BUILD_SRC/libs/$1 install - common_run cd $BASE -} - -# Run the main program. -common_parse_arguments $@ -common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC - - -for ARCH in $BUILD_ARCH -do - case $ARCH in - "armeabi") - OARCH="arm" - ;; - "armeabi-v7a") - OARCH="arm" - ;; - "arm64-v8a") - OARCH="arm64" - ;; - *) - OARCH=$ARCH - ;; - esac - - echo "$ARCH=$OARCH" - - build $OARCH $NDK_TARGET - - if [ ! -d $BUILD_DST/$ARCH/include ]; - then - common_run mkdir -p $BUILD_DST/$ARCH/include - fi - - common_run cp -L -r $BUILD_SRC/libs/$OARCH/include/ $BUILD_DST/$ARCH/ - if [ ! -d $BUILD_DST/$ARCH ]; - then - common_run mkdir -p $BUILD_DST/$ARCH - fi - common_run cp -L $BUILD_SRC/libs/$OARCH/lib/*.so $BUILD_DST/$ARCH/ -done diff --git a/scripts/android-build-openssl.sh b/scripts/android-build-openssl.sh deleted file mode 100755 index 834e53a..0000000 --- a/scripts/android-build-openssl.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -SCM_URL=https://github.com/openssl/openssl -SCM_TAG=master - -COMPILER=4.9 - -source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh - -function build { - if [ $# -ne 2 ]; - then - echo "Invalid arguments $@" - exit 1 - fi - - CONFIG=$1 - DST_PREFIX=$2 - - common_run export CC=clang - common_run export PATH=$(${SCRIPT_PATH}/toolchains_path.py --ndk ${ANDROID_NDK}):$ORG_PATH - common_run export ANDROID_NDK - - echo "CONFIG=$CONFIG" - echo "DST_PREFIX=$DST_PREFIX" - echo "PATH=$PATH" - - BASE=$(pwd) - DST_DIR=$BUILD_DST/$DST_PREFIX - common_run cd $BUILD_SRC - common_run ./Configure ${CONFIG} -D__ANDROID_API__=$NDK_TARGET - common_run make SHLIB_EXT=.so -j build_libs - - if [ ! -d $DST_DIR ]; - then - common_run mkdir -p $DST_DIR - fi - - common_run cp *.so $DST_DIR/ - common_run cd $BASE -} - -# Run the main program. -common_parse_arguments $@ -common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC - -ORG_PATH=$PATH -for ARCH in $BUILD_ARCH -do - - case $ARCH in - "armeabi-v7a") - build "android-arm" "armeabi-v7a" - ;; - "x86") - build "android-x86" "x86" - ;; - "arm64-v8a") - build "android-arm64" "arm64-v8a" - ;; - "x86_64") - build "android-x86_64" "x86_64" - ;; - *) - echo "[WARNING] Skipping unsupported architecture $ARCH" - continue - ;; - esac -done - -if [ ! -d $BUILD_DST/$ARCH/include ]; -then - common_run mkdir -p $BUILD_DST/$ARCH/include -fi -common_run cp -L -R $BUILD_SRC/include/openssl $BUILD_DST/$ARCH/include/ - diff --git a/scripts/android-build.conf b/scripts/android-build.conf deleted file mode 100644 index c8eb40c..0000000 --- a/scripts/android-build.conf +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Android build confguration -# -# Note: This is a simple configuration to build all -# architectures in one rush. -# Since android 64 bit support was introduced with NDK API 21 -# this is the minimal common denominator. -# If you require support for older NDK API levels, -# create seperate configurations for each NDK API level -# and architecture you want to support. -WITH_JPEG=0 -WITH_OPENH264=0 -WITH_OPENSSL=1 -BUILD_DEPS=1 -DEPS_ONLY=0 -NDK_TARGET=26 - -JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1j - -SRC_DIR=$SCRIPT_PATH/.. -BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs -BUILD_SRC=$SRC_DIR/build - -CMAKE_BUILD_TYPE=Debug - -BUILD_ARCH="armeabi-v7a x86 arm64-v8a x86_64" diff --git a/uwac/libuwac/uwac-priv.h b/uwac/libuwac/uwac-priv.h index aed3898..cbc5704 100644 --- a/uwac/libuwac/uwac-priv.h +++ b/uwac/libuwac/uwac-priv.h @@ -255,6 +255,14 @@ struct uwac_window int pointer_current_cursor; }; +/**@brief data to pass to wl_buffer release listener */ +struct uwac_buffer_release_data +{ + UwacWindow* window; + int bufferIdx; +}; +typedef struct uwac_buffer_release_data UwacBufferReleaseData; + /* in uwa-display.c */ UwacEvent* UwacDisplayNewEvent(UwacDisplay* d, int type); int UwacDisplayWatchFd(UwacDisplay* display, int fd, uint32_t events, UwacTask* task); diff --git a/uwac/libuwac/uwac-window.c b/uwac/libuwac/uwac-window.c index bf70af2..8e6f08d 100644 --- a/uwac/libuwac/uwac-window.c +++ b/uwac/libuwac/uwac-window.c @@ -46,7 +46,8 @@ static int bppFromShmFormat(enum wl_shm_format format) static void buffer_release(void* data, struct wl_buffer* buffer) { - UwacBuffer* uwacBuffer = (UwacBuffer*)data; + UwacBufferReleaseData* releaseData = data; + UwacBuffer* uwacBuffer = &releaseData->window->buffers[releaseData->bufferIdx]; uwacBuffer->used = false; } @@ -64,7 +65,10 @@ static void UwacWindowDestroyBuffers(UwacWindow* w) #else region16_uninit(&buffer->damage); #endif + UwacBufferReleaseData* releaseData = + (UwacBufferReleaseData*)wl_buffer_get_user_data(buffer->wayland_buffer); wl_buffer_destroy(buffer->wayland_buffer); + free(releaseData); munmap(buffer->data, buffer->size); } @@ -342,7 +346,8 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32 for (i = 0; i < nbuffers; i++) { - UwacBuffer* buffer = &w->buffers[w->nbuffers + i]; + int bufferIdx = w->nbuffers + i; + UwacBuffer* buffer = &w->buffers[bufferIdx]; #ifdef HAVE_PIXMAN_REGION pixman_region32_init(&buffer->damage); #else @@ -352,7 +357,10 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32 buffer->size = allocSize; buffer->wayland_buffer = wl_shm_pool_create_buffer(pool, allocSize * i, width, height, w->stride, format); - wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, buffer); + UwacBufferReleaseData* listener_data = xmalloc(sizeof(UwacBufferReleaseData)); + listener_data->window = w; + listener_data->bufferIdx = bufferIdx; + wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, listener_data); } wl_shm_pool_destroy(pool); diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 620f9a7..3bad25b 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -51,7 +51,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.5.0") +set(RAW_VERSION_STRING "2.6.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt index a2d0dda..c1645b9 100644 --- a/winpr/libwinpr/crt/CMakeLists.txt +++ b/winpr/libwinpr/crt/CMakeLists.txt @@ -30,7 +30,7 @@ endif(NOT WITH_ICU) if (WITH_ICU) find_package(ICU REQUIRED i18n uc io) - include_directories(${ICU_INCLUDE_DIRS}) + winpr_include_directory_add(${ICU_INCLUDE_DIRS}) winpr_library_add_private(${ICU_LIBRARIES}) endif (WITH_ICU) diff --git a/winpr/libwinpr/sspicli/sspicli.c b/winpr/libwinpr/sspicli/sspicli.c index 0394169..5a13b99 100644 --- a/winpr/libwinpr/sspicli/sspicli.c +++ b/winpr/libwinpr/sspicli/sspicli.c @@ -21,8 +21,11 @@ #include "config.h" #endif +#include #include +#define WINPR_ASSERT(x) assert(x) + /** * sspicli.dll: * @@ -60,6 +63,12 @@ #include #endif +#if defined(HAVE_GETPWUID_R) +#include +#include +#include +#endif + #include #include @@ -200,31 +209,33 @@ BOOL LogonUserExW(LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize) { - size_t length; - char login[MAX_PATH]; + WINPR_ASSERT(lpNameBuffer); + WINPR_ASSERT(nSize); switch (NameFormat) { case NameSamCompatible: -#ifndef HAVE_GETLOGIN_R - strncpy(login, getlogin(), sizeof(login)); -#else - if (getlogin_r(login, sizeof(login)) != 0) +#if defined(HAVE_GETPWUID_R) + { + int rc; + struct passwd pwd = { 0 }; + struct passwd* result = NULL; + uid_t uid = getuid(); + + rc = getpwuid_r(uid, &pwd, lpNameBuffer, *nSize, &result); + if (rc != 0) return FALSE; + if (result == NULL) + return FALSE; + } +#elif defined(HAVE_GETLOGIN_R) + if (getlogin_r(lpNameBuffer, *nSize) != 0) + return FALSE; +#else + strncpy(lpNameBuffer, getlogin(), *nSize); #endif - length = strlen(login); - - if (*nSize >= length) - { - CopyMemory(lpNameBuffer, login, length + 1); - return TRUE; - } - else - { - *nSize = length + 1; - } - - break; + *nSize = strnlen(lpNameBuffer, *nSize); + return TRUE; case NameFullyQualifiedDN: case NameDisplay: @@ -245,7 +256,29 @@ BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG BOOL GetUserNameExW(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize) { - return 0; + int res; + BOOL rc = FALSE; + char* name; + + WINPR_ASSERT(nSize); + WINPR_ASSERT(lpNameBuffer); + + name = calloc(1, *nSize + 1); + if (!name) + goto fail; + + if (!GetUserNameExA(NameFormat, name, nSize)) + goto fail; + + res = ConvertToUnicode(CP_UTF8, 0, name, -1, &lpNameBuffer, *nSize); + if (res < 0) + goto fail; + + *nSize = res + 1; + rc = TRUE; +fail: + free(name); + return rc; } #endif diff --git a/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c b/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c index b0bf8f2..30086d4 100644 --- a/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c +++ b/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c @@ -1,15 +1,14 @@ - #include #include #include #include -#define THREADS 24 +#define THREADS 8 static DWORD WINAPI test_thread(LPVOID arg) { - long timeout = 100 + (rand() % 1000); + long timeout = 30 + (rand() % 100); WINPR_UNUSED(arg); Sleep(timeout); ExitThread(0); @@ -22,7 +21,7 @@ static int start_threads(DWORD count, HANDLE* threads) for (i = 0; i < count; i++) { - threads[i] = CreateThread(NULL, 0, test_thread, NULL, 0, NULL); + threads[i] = CreateThread(NULL, 0, test_thread, NULL, CREATE_SUSPENDED, NULL); if (!threads[i]) { @@ -31,38 +30,45 @@ static int start_threads(DWORD count, HANDLE* threads) } } + for (i = 0; i < count; i++) + ResumeThread(threads[i]); return 0; } static int close_threads(DWORD count, HANDLE* threads) { + int rc = 0; DWORD i; for (i = 0; i < count; i++) { + if (!threads[i]) + continue; + if (!CloseHandle(threads[i])) { fprintf(stderr, "%s: CloseHandle [%" PRIu32 "] failure\n", __FUNCTION__, i); - return -1; + rc = -1; } + threads[i] = NULL; } - return 0; + return rc; } static BOOL TestWaitForAll(void) { BOOL rc = FALSE; DWORD ret; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } - ret = WaitForMultipleObjects(THREADS, threads, TRUE, 50); + ret = WaitForMultipleObjects(THREADS, threads, TRUE, 10); if (ret != WAIT_TIMEOUT) { fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, timeout 50 failed, ret=%d\n", @@ -76,14 +82,14 @@ static BOOL TestWaitForAll(void) goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } @@ -91,12 +97,12 @@ static BOOL TestWaitOne(void) { BOOL rc = FALSE; DWORD ret; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } ret = WaitForMultipleObjects(THREADS, threads, FALSE, INFINITE); @@ -112,14 +118,14 @@ static BOOL TestWaitOne(void) goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } @@ -127,15 +133,15 @@ static BOOL TestWaitOneTimeout(void) { BOOL rc = FALSE; DWORD ret; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } - ret = WaitForMultipleObjects(THREADS, threads, FALSE, 50); + ret = WaitForMultipleObjects(THREADS, threads, FALSE, 1); if (ret != WAIT_TIMEOUT) { fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__, @@ -148,15 +154,14 @@ static BOOL TestWaitOneTimeout(void) fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__); goto fail; } - + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } @@ -164,12 +169,12 @@ static BOOL TestWaitOneTimeoutMultijoin(void) { BOOL rc = FALSE; DWORD ret, i; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } for (i = 0; i < THREADS; i++) @@ -177,7 +182,7 @@ static BOOL TestWaitOneTimeoutMultijoin(void) ret = WaitForMultipleObjects(THREADS, threads, FALSE, 0); if (ret != WAIT_TIMEOUT) { - fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__, + fprintf(stderr, "%s: WaitForMultipleObjects timeout 0 failed, ret=%d\n", __FUNCTION__, ret); goto fail; } @@ -189,34 +194,37 @@ static BOOL TestWaitOneTimeoutMultijoin(void) goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } static BOOL TestDetach(void) { - HANDLE threads[THREADS]; + BOOL rc = FALSE; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - return TRUE; + return rc; } int TestSynchMultipleThreads(int argc, char* argv[]) diff --git a/winpr/libwinpr/utils/sam.c b/winpr/libwinpr/utils/sam.c index 094475f..7270bf6 100644 --- a/winpr/libwinpr/utils/sam.c +++ b/winpr/libwinpr/utils/sam.c @@ -173,23 +173,29 @@ static void SamLookupFinish(WINPR_SAM* sam) static void HexStrToBin(const char* str, BYTE* bin, size_t length) { size_t i; - CharUpperBuffA(str, length * 2); for (i = 0; i < length; i++) { - bin[i] = 0; + char cur = str[2 * i]; + char curNext = str[2 * i + 1]; + BYTE* curBin = &bin[i]; - if ((str[i * 2] >= '0') && (str[i * 2] <= '9')) - bin[i] |= (str[i * 2] - '0') << 4; + CharUpperBuffA(&cur, 1); + CharUpperBuffA(&curNext, 1); - if ((str[i * 2] >= 'A') && (str[i * 2] <= 'F')) - bin[i] |= (str[i * 2] - 'A' + 10) << 4; + *curBin = 0; - if ((str[i * 2 + 1] >= '0') && (str[i * 2 + 1] <= '9')) - bin[i] |= (str[i * 2 + 1] - '0'); + if ((cur >= '0') && (cur <= '9')) + *curBin |= (cur - '0') << 4; - if ((str[i * 2 + 1] >= 'A') && (str[i * 2 + 1] <= 'F')) - bin[i] |= (str[i * 2 + 1] - 'A' + 10); + if ((cur >= 'A') && (cur <= 'F')) + *curBin |= (cur - 'A' + 10) << 4; + + if ((curNext >= '0') && (curNext <= '9')) + *curBin |= (curNext - '0'); + + if ((curNext >= 'A') && (curNext <= 'F')) + *curBin |= (curNext - 'A' + 10); } }