From 3ac50697a092f0b317b7693cb994f18e0bef9a37 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 30 Jun 2021 13:04:22 +0200 Subject: [PATCH] Added RDPGFX_CODECID_UNCOMPRESSED path to shadow --- server/shadow/CMakeLists.txt | 2 +- server/shadow/shadow.c | 15 +++ server/shadow/shadow_client.c | 217 +++++++++++++++++++++++----------- server/shadow/shadow_server.c | 17 +++ 4 files changed, 184 insertions(+), 67 deletions(-) diff --git a/server/shadow/CMakeLists.txt b/server/shadow/CMakeLists.txt index c95bdb0f5..5140faf89 100644 --- a/server/shadow/CMakeLists.txt +++ b/server/shadow/CMakeLists.txt @@ -341,7 +341,7 @@ endif() add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-shadow-subsystem freerdp-shadow winpr) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-shadow-subsystem freerdp-shadow freerdp winpr) target_link_libraries(${MODULE_NAME} PRIVATE ${${MODULE_PREFIX}_LIBS}) diff --git a/server/shadow/shadow.c b/server/shadow/shadow.c index c61978ed4..d773c2560 100644 --- a/server/shadow/shadow.c +++ b/server/shadow/shadow.c @@ -79,6 +79,12 @@ int main(int argc, char** argv) "nla extended protocol security" }, { "sam-file", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "NTLM SAM file for NLA authentication" }, + { "gfx-progressive", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, + "Allow GFX progressive codec" }, + { "gfx-avc420", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, + "Allow GFX AVC420 codec" }, + { "gfx-avc444", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, + "Allow GFX AVC444 codec" }, { "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" }, { "buildconfig", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_BUILDCONFIG, NULL, NULL, NULL, @@ -105,6 +111,15 @@ int main(int argc, char** argv) settings->TlsSecurity = TRUE; settings->RdpSecurity = TRUE; + /* By default allow all GFX modes. + * This can be changed with command line flags [+|-]gfx-CODEC + */ + freerdp_settings_set_bool(settings, FreeRDP_GfxH264, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444v2, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, TRUE); + freerdp_settings_set_bool(settings, FreeRDP_GfxProgressiveV2, TRUE); + #ifdef WITH_SHADOW_X11 server->authentication = TRUE; #else diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 907b2da21..5de468b2c 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -136,16 +136,27 @@ static INLINE void shadow_client_free_queued_message(void* obj) } } -static BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) +static BOOL shadow_client_context_new(freerdp_peer* peer, rdpContext* context) { const char bind_address[] = "bind-address,"; + rdpShadowClient* client = (rdpShadowClient*)context; rdpSettings* settings; rdpShadowServer* server; const wObject cb = { NULL, NULL, NULL, shadow_client_free_queued_message, NULL }; + + WINPR_ASSERT(client); + WINPR_ASSERT(peer); + server = (rdpShadowServer*)peer->ContextExtra; + WINPR_ASSERT(server); + client->server = server; client->subsystem = server->subsystem; + WINPR_ASSERT(client->subsystem); + settings = peer->settings; + WINPR_ASSERT(settings); + settings->ColorDepth = 32; settings->NSCodec = TRUE; settings->RemoteFxCodec = TRUE; @@ -220,10 +231,16 @@ fail_cert_file: return FALSE; } -static void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) +static void shadow_client_context_free(freerdp_peer* peer, rdpContext* context) { - rdpShadowServer* server = client->server; + rdpShadowClient* client = (rdpShadowClient*)context; + rdpShadowServer* server; + + WINPR_ASSERT(context); WINPR_UNUSED(peer); + server = client->server; + WINPR_ASSERT(server); + ArrayList_Remove(server->clients, (void*)client); if (client->encoder) @@ -656,16 +673,27 @@ static BOOL shadow_are_caps_filtered(const rdpSettings* settings, UINT32 caps) return TRUE; } -static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, BOOL h264, - const RDPGFX_CAPSET* capsSets, UINT32 capsSetCount, - UINT32 capsVersion, UINT* rc) +static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, rdpShadowClient* client, + BOOL h264, const RDPGFX_CAPSET* capsSets, + UINT32 capsSetCount, UINT32 capsVersion, UINT* rc) { - UINT32 flags = 0; UINT32 index; - rdpSettings* settings; - settings = context->rdpcontext->settings; + const rdpSettings* srvSettings; + rdpSettings* clientSettings; - if (shadow_are_caps_filtered(settings, capsVersion)) + WINPR_ASSERT(context); + WINPR_ASSERT(client); + WINPR_ASSERT(capsSets || (capsSetCount == 0)); + WINPR_ASSERT(rc); + + WINPR_ASSERT(context->rdpcontext); + srvSettings = context->rdpcontext->settings; + WINPR_ASSERT(srvSettings); + + clientSettings = client->context.settings; + WINPR_ASSERT(clientSettings); + + if (shadow_are_caps_filtered(srvSettings, capsVersion)) return FALSE; for (index = 0; index < capsSetCount; index++) @@ -674,25 +702,39 @@ static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, BOOL h if (currentCaps->version == capsVersion) { + UINT32 flags; + BOOL avc444v2 = FALSE; + BOOL avc444 = FALSE; + BOOL avc420 = FALSE; + BOOL progressive = FALSE; RDPGFX_CAPSET caps = *currentCaps; - RDPGFX_CAPS_CONFIRM_PDU pdu; + RDPGFX_CAPS_CONFIRM_PDU pdu = { 0 }; pdu.capsSet = ∩︀ - if (settings) - { - flags = pdu.capsSet->flags; - settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE); + flags = pdu.capsSet->flags; - if (h264) - settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 = - !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED); - else - { - settings->GfxAVC444v2 = settings->GfxAVC444 = settings->GfxH264 = FALSE; - pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; - } - } + clientSettings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE); + avc444v2 = avc444 = !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED); + if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxAVC444v2) || !h264) + avc444v2 = FALSE; + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, avc444v2); + if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxAVC444) || !h264) + avc444 = FALSE; + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, avc444); + if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxH264) || !h264) + avc420 = FALSE; + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, avc420); + + progressive = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxProgressive); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxProgressive, progressive); + progressive = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxProgressiveV2); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxProgressiveV2, progressive); + + if (!avc444v2 && !avc444 && !avc420) + pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; + + WINPR_ASSERT(context->CapsConfirm); *rc = context->CapsConfirm(context, &pdu); return TRUE; } @@ -711,50 +753,68 @@ static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context, { UINT16 index; UINT rc = ERROR_INTERNAL_ERROR; + const rdpSettings* srvSettings; + rdpSettings* clientSettings; BOOL h264 = FALSE; - rdpSettings* settings = context->rdpcontext->settings; + UINT32 flags = 0; - rdpShadowClient* client = (rdpShadowClient*)context->custom; + rdpShadowClient* client; + + WINPR_ASSERT(context); + WINPR_ASSERT(capsAdvertise); + + client = (rdpShadowClient*)context->custom; + WINPR_ASSERT(client); + WINPR_ASSERT(context->rdpcontext); + + srvSettings = context->rdpcontext->settings; + WINPR_ASSERT(srvSettings); + + clientSettings = client->context.settings; + WINPR_ASSERT(clientSettings); #ifdef WITH_GFX_H264 - if (shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444) >= 0) - h264 = TRUE; - + h264 = + (shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444) >= 0); +#else + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE); #endif /* Request full screen update for new gfx channel */ if (!shadow_client_refresh_rect(&client->context, 0, NULL)) return rc; - if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, + if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_106, &rc)) return rc; - if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, + if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_105, &rc)) return rc; - if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, + if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_104, &rc)) return rc; - if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, + if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_103, &rc)) return rc; - if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, + if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_102, &rc)) return rc; - if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, + if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_101, &rc)) return rc; - if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, + if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_10, &rc)) return rc; - if (!shadow_are_caps_filtered(settings, RDPGFX_CAPVERSION_81)) + if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_81)) { for (index = 0; index < capsAdvertise->capsSetCount; index++) { @@ -766,29 +826,35 @@ static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context, RDPGFX_CAPS_CONFIRM_PDU pdu; pdu.capsSet = ∩︀ - if (settings) - { flags = pdu.capsSet->flags; - settings->GfxAVC444v2 = settings->GfxAVC444 = FALSE; - settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT); - settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE); -#ifndef WITH_GFX_H264 - settings->GfxH264 = FALSE; - pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED; -#else - if (h264) - settings->GfxH264 = (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED); - else - settings->GfxH264 = FALSE; -#endif - } - return context->CapsConfirm(context, &pdu); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE); + + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxThinClient, + (flags & RDPGFX_CAPS_FLAG_THINCLIENT)); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache, + (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE)); + +#ifndef WITH_GFX_H264 + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE); + pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED; +#else + + if (h264) + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, + (flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED)); + else + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE); +#endif + + WINPR_ASSERT(context->CapsConfirm); + return context->CapsConfirm(context, &pdu); } } } - if (!shadow_are_caps_filtered(settings, RDPGFX_CAPVERSION_8)) + if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_8)) { for (index = 0; index < capsAdvertise->capsSetCount; index++) { @@ -799,14 +865,18 @@ static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context, RDPGFX_CAPSET caps = *currentCaps; RDPGFX_CAPS_CONFIRM_PDU pdu; pdu.capsSet = ∩︀ + flags = pdu.capsSet->flags; - if (settings) - { - flags = pdu.capsSet->flags; - settings->GfxThinClient = (flags & RDPGFX_CAPS_FLAG_THINCLIENT); - settings->GfxSmallCache = (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE); - } + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxThinClient, + (flags & RDPGFX_CAPS_FLAG_THINCLIENT)); + freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache, + (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE)); + + WINPR_ASSERT(context->CapsConfirm); return context->CapsConfirm(context, &pdu); } } @@ -829,13 +899,13 @@ static INLINE UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM* ha * * @return TRUE on success */ -static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* pSrcData, +static BOOL shadow_client_send_surface_gfx(const rdpShadowClient* client, const BYTE* pSrcData, UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc, UINT16 nWidth, UINT16 nHeight) { UINT error = CHANNEL_RC_OK; - rdpContext* context = (rdpContext*)client; - rdpSettings* settings; + const rdpContext* context = (const rdpContext*)client; + const rdpSettings* settings; rdpShadowEncoder* encoder; RDPGFX_SURFACE_COMMAND cmd; RDPGFX_START_FRAME_PDU cmdstart; @@ -965,7 +1035,7 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* return FALSE; } } - else + else if (freerdp_settings_get_bool(settings, FreeRDP_GfxProgressive)) { INT32 rc; REGION16 region; @@ -1011,6 +1081,21 @@ static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* return FALSE; } } + else + { + cmd.data = pSrcData; + cmd.length = nSrcStep * nHeight; + cmd.codecId = RDPGFX_CODECID_UNCOMPRESSED; + + IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, &cmd, &cmdstart, + &cmdend); + + if (error) + { + WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error); + return FALSE; + } + } return TRUE; } @@ -2055,8 +2140,8 @@ BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer) server = (rdpShadowServer*)listener->info; peer->ContextExtra = (void*)server; peer->ContextSize = sizeof(rdpShadowClient); - peer->ContextNew = (psPeerContextNew)shadow_client_context_new; - peer->ContextFree = (psPeerContextFree)shadow_client_context_free; + peer->ContextNew = shadow_client_context_new; + peer->ContextFree = shadow_client_context_free; peer->settings = freerdp_settings_clone(server->settings); if (!freerdp_peer_context_new(peer)) diff --git a/server/shadow/shadow_server.c b/server/shadow/shadow_server.c index 9f982d81e..1427b5c41 100644 --- a/server/shadow/shadow_server.c +++ b/server/shadow/shadow_server.c @@ -365,6 +365,23 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a if (!WLog_AddStringLogFilters(arg->Value)) return COMMAND_LINE_ERROR; } + CommandLineSwitchCase(arg, "gfx-progressive") + { + if (!freerdp_settings_set_bool(settings, FreeRDP_GfxProgressive, + arg->Value ? TRUE : FALSE)) + return COMMAND_LINE_ERROR; + } + CommandLineSwitchCase(arg, "gfx-avc420") + { + if (!freerdp_settings_set_bool(settings, FreeRDP_GfxH264, arg->Value ? TRUE : FALSE)) + return COMMAND_LINE_ERROR; + } + CommandLineSwitchCase(arg, "gfx-avc444") + { + if (!freerdp_settings_set_bool(settings, FreeRDP_GfxAVC444v2, + arg->Value ? TRUE : FALSE)) + return COMMAND_LINE_ERROR; + } CommandLineSwitchDefault(arg) { }