From afa70e464a6f9550ac0f64527a94df1935bedf9b Mon Sep 17 00:00:00 2001 From: Nexarian Date: Sat, 16 Dec 2023 12:49:56 -0500 Subject: [PATCH 01/21] Initial rfx progressive integration - Mostly base functions and utilities necessary to enable RFX Progressive - Add more EGFX work & mode flags. - Update encoder. - Does not yet include caps determination to enable RFX progressive (yet). - Update protocol constants --- common/Makefile.am | 2 +- common/ms-rdpbcgr.h | 32 +++++++++----- common/xrdp_client_info.h | 8 ++++ common/xrdp_constants.h | 46 +++++++++++++++++++++ libxrdp/xrdp_sec.c | 25 ++++++++--- xrdp/xrdp_encoder.c | 87 ++++++++++++++++++++++++++++++--------- xrdp/xrdp_encoder.h | 9 ++++ xrdp/xrdp_mm.c | 8 +++- xrdp/xrdp_painter.c | 73 ++++++++++++++++++++------------ xrdp/xrdp_types.h | 10 ++++- xrdp/xrdp_wm.c | 17 ++++++-- 11 files changed, 246 insertions(+), 71 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index 141addc8..baed9f0d 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -71,6 +71,6 @@ libcommon_la_SOURCES = \ $(PIXMAN_SOURCES) libcommon_la_LIBADD = \ - -lpthread \ + -lpthread -lrt \ $(OPENSSL_LIBS) \ $(DLOPEN_LIBS) diff --git a/common/ms-rdpbcgr.h b/common/ms-rdpbcgr.h index 517b777c..6e390535 100644 --- a/common/ms-rdpbcgr.h +++ b/common/ms-rdpbcgr.h @@ -52,19 +52,29 @@ /* TS_UD_HEADER: type ((2.2.1.3.1) */ /* TODO: to be renamed */ -#define SEC_TAG_CLI_INFO 0xc001 /* CS_CORE? */ -#define SEC_TAG_CLI_CRYPT 0xc002 /* CS_SECURITY? */ -#define SEC_TAG_CLI_CHANNELS 0xc003 /* CS_CHANNELS? */ -#define SEC_TAG_CLI_4 0xc004 /* CS_CLUSTER? */ -#define SEC_TAG_CLI_MONITOR 0xc005 /* CS_MONITOR */ -#define SEC_TAG_CLI_MONITOR_EX 0xc008 /* CS_MONITOR_EX */ +#define SEC_TAG_CLI_INFO 0xc001 /* CS_CORE? */ +#define SEC_TAG_CLI_CRYPT 0xc002 /* CS_SECURITY? */ +#define SEC_TAG_CLI_CHANNELS 0xc003 /* CS_CHANNELS? */ +#define SEC_TAG_CLI_4 0xc004 /* CS_CLUSTER? */ +#define SEC_TAG_CLI_MONITOR 0xc005 /* CS_MONITOR */ +#define SEC_TAG_CLI_MONITOR_EX 0xc008 /* CS_MONITOR_EX */ /* Client Core Data: colorDepth, postBeta2ColorDepth (2.2.1.3.2) */ -#define RNS_UD_COLOR_4BPP 0xCA00 -#define RNS_UD_COLOR_8BPP 0xCA01 -#define RNS_UD_COLOR_16BPP_555 0xCA02 -#define RNS_UD_COLOR_16BPP_565 0xCA03 -#define RNS_UD_COLOR_24BPP 0xCA04 +#define RNS_UD_COLOR_4BPP 0xCA00 +#define RNS_UD_COLOR_8BPP 0xCA01 +#define RNS_UD_COLOR_16BPP_555 0xCA02 +#define RNS_UD_COLOR_16BPP_565 0xCA03 +#define RNS_UD_COLOR_24BPP 0xCA04 + +/* Client Core Data: supportedColorDepths (2.2.1.3.2) */ +#define RNS_UD_24BPP_SUPPORT 0x0001 +#define RNS_UD_16BPP_SUPPORT 0x0002 +#define RNS_UD_15BPP_SUPPORT 0x0004 +#define RNS_UD_32BPP_SUPPORT 0x0008 + +/* Client Core Data: earlyCapabilityFlags (2.2.1.3.2) */ +#define RNS_UD_CS_WANT_32BPP_SESSION 0x0002 +#define RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL 0x0100 /* Client Core Data: connectionType (2.2.1.3.2) */ #define CONNECTION_TYPE_MODEM 0x01 diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index f2d91ad7..a588f16c 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -215,6 +215,14 @@ struct xrdp_client_info unsigned int session_physical_height; /* in mm */ int large_pointer_support_flags; + int gfx; +}; + +enum xrdp_encoder_flags +{ + NONE = 0, + ENCODE_COMPLETE = 1 << 0, + GFX_PROGRESSIVE_RFX = 1 << 1 }; /* yyyymmdd of last incompatible change to xrdp_client_info */ diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h index 231d494a..9ab9d179 100644 --- a/common/xrdp_constants.h +++ b/common/xrdp_constants.h @@ -291,4 +291,50 @@ #define XR_RDP_SCAN_LSHIFT 42 #define XR_RDP_SCAN_ALT 56 +// Since we're not guaranteed to have pixman, copy these directives. +#define XRDP_PIXMAN_TYPE_ARGB 2 +#define XRDP_PIXMAN_TYPE_ABGR 3 +#define XRDP_PIXMAN_FORMAT(bpp,type,a,r,g,b) (((bpp) << 24) | \ + ((type) << 16) | \ + ((a) << 12) | \ + ((r) << 8) | \ + ((g) << 4) | \ + ((b))) + +#define XRDP_a8b8g8r8 \ + XRDP_PIXMAN_FORMAT(32, XRDP_PIXMAN_TYPE_ABGR, 8, 8, 8, 8) + +#define XRDP_a8r8g8b8 \ + XRDP_PIXMAN_FORMAT(32, XRDP_PIXMAN_TYPE_ARGB, 8, 8, 8, 8) + +#define XRDP_r5g6b5 \ + XRDP_PIXMAN_FORMAT(16, XRDP_PIXMAN_TYPE_ARGB, 0, 5, 6, 5) + +#define XRDP_a1r5g5b5 \ + XRDP_PIXMAN_FORMAT(16, XRDP_PIXMAN_TYPE_ARGB, 1, 5, 5, 5) + +#define XRDP_r3g3b2 \ + XRDP_PIXMAN_FORMAT(8, XRDP_PIXMAN_TYPE_ARGB, 0, 3, 3, 2) + +// The last used constant in pixman is 63, so use 64+ +#define XRDP_nv12 \ + XRDP_PIXMAN_FORMAT(12, 64, 0, 0, 0, 0) + +#define XRDP_i420 \ + XRDP_PIXMAN_FORMAT(12, 65, 0, 0, 0, 0) + +#define XRDP_nv12_709fr \ + XRDP_PIXMAN_FORMAT(12, 66, 0, 0, 0, 0) + +#define XRDP_yuv444_709fr \ + XRDP_PIXMAN_FORMAT(32, 67, 0, 0, 0, 0) + +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegfx/8131c1bc-1af8-4907-a05a-f72f4581160f +#define XRDP_yuv444_v1_stream_709fr \ + XRDP_PIXMAN_FORMAT(32, 68, 0, 0, 0, 0) + +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegfx/781406c3-5e24-4f2b-b6ff-42b76bf64f6d +#define XRDP_yuv444_v2_stream_709fr \ + XRDP_PIXMAN_FORMAT(32, 69, 0, 0, 0, 0) + #endif diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 20665dfc..6c2057ae 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -2114,10 +2114,14 @@ xrdp_sec_process_mcs_data_CS_CORE(struct xrdp_sec *self, struct stream *s) in_uint16_le(s, supportedColorDepths); LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_UD_CS_CORE " " supportedColorDepths %s", - supportedColorDepths == 0x0001 ? "RNS_UD_24BPP_SUPPORT" : - supportedColorDepths == 0x0002 ? "RNS_UD_16BPP_SUPPORT" : - supportedColorDepths == 0x0004 ? "RNS_UD_15BPP_SUPPORT" : - supportedColorDepths == 0x0008 ? "RNS_UD_32BPP_SUPPORT" : + supportedColorDepths == RNS_UD_24BPP_SUPPORT + ? "RNS_UD_24BPP_SUPPORT" : + supportedColorDepths == RNS_UD_16BPP_SUPPORT + ? "RNS_UD_16BPP_SUPPORT" : + supportedColorDepths == RNS_UD_15BPP_SUPPORT + ? "RNS_UD_15BPP_SUPPORT" : + supportedColorDepths == RNS_UD_32BPP_SUPPORT + ? "RNS_UD_32BPP_SUPPORT" : "unknown"); if (!s_check_rem(s, 2)) @@ -2129,11 +2133,20 @@ xrdp_sec_process_mcs_data_CS_CORE(struct xrdp_sec *self, struct stream *s) LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_UD_CS_CORE " " earlyCapabilityFlags 0x%4.4x", earlyCapabilityFlags); - if ((earlyCapabilityFlags & 0x0002) && (supportedColorDepths & 0x0008)) + if ((earlyCapabilityFlags & RNS_UD_CS_WANT_32BPP_SESSION) + && (supportedColorDepths & RNS_UD_32BPP_SUPPORT)) { client_info->bpp = 32; } - + if (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) + { + LOG(LOG_LEVEL_INFO, "client supports gfx protocol"); + self->rdp_layer->client_info.gfx = 1; + } + else + { + LOG_DEVEL(LOG_LEVEL_INFO, "client DOES NOT support gfx"); + } if (!s_check_rem(s, 64)) { return 0; diff --git a/xrdp/xrdp_encoder.c b/xrdp/xrdp_encoder.c index 03203cd7..8c3d9d0b 100644 --- a/xrdp/xrdp_encoder.c +++ b/xrdp/xrdp_encoder.c @@ -32,10 +32,17 @@ #include "rfxcodec_encode.h" #endif - - #define XRDP_SURCMD_PREFIX_BYTES 256 +#ifdef XRDP_RFXCODEC +/* LH3 LL3, HH3 HL3, HL2 LH2, LH1 HH2, HH1 HL1 todo check this */ +static const unsigned char g_rfx_quantization_values[] = +{ + 0x66, 0x66, 0x77, 0x88, 0x98, + 0x76, 0x77, 0x88, 0x98, 0xA9 +}; +#endif + /*****************************************************************************/ static int process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc); @@ -77,16 +84,24 @@ xrdp_encoder_create(struct xrdp_mm *mm) client_info = mm->wm->client_info; + /* RemoteFX 7.1 requires LAN but GFX does not */ if (client_info->mcs_connection_type != CONNECTION_TYPE_LAN) { - return 0; + if ((mm->egfx_flags & (XRDP_EGFX_H264 | XRDP_EGFX_RFX_PRO)) == 0) + { + return 0; + } } if (client_info->bpp < 24) { return 0; } - self = (struct xrdp_encoder *)g_malloc(sizeof(struct xrdp_encoder), 1); + self = g_new0(struct xrdp_encoder, 1); + if (self == NULL) + { + return NULL; + } self->mm = mm; if (client_info->jpeg_codec_id != 0) @@ -96,12 +111,29 @@ xrdp_encoder_create(struct xrdp_mm *mm) self->in_codec_mode = 1; self->codec_quality = client_info->jpeg_prop[0]; client_info->capture_code = 0; - client_info->capture_format = - /* XRDP_a8b8g8r8 */ - (32 << 24) | (3 << 16) | (8 << 12) | (8 << 8) | (8 << 4) | 8; + client_info->capture_format = XRDP_a8b8g8r8; self->process_enc = process_enc_jpg; } #ifdef XRDP_RFXCODEC + else if (mm->egfx_flags & XRDP_EGFX_RFX_PRO) + { + LOG(LOG_LEVEL_INFO, + "xrdp_encoder_create: starting gfx rfx pro codec session"); + self->in_codec_mode = 1; + client_info->capture_code = 2; + self->process_enc = process_enc_rfx; + self->gfx = 1; + self->quants = (const char *) g_rfx_quantization_values; + self->num_quants = 2; + self->quant_idx_y = 0; + self->quant_idx_u = 1; + self->quant_idx_v = 1; + self->codec_handle = rfxcodec_encode_create( + mm->wm->screen->width, + mm->wm->screen->height, + RFX_FORMAT_YUV, + RFX_FLAGS_RLGR1 | RFX_FLAGS_PRO1); + } else if (client_info->rfx_codec_id != 0) { LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: starting rfx codec session"); @@ -120,9 +152,7 @@ xrdp_encoder_create(struct xrdp_mm *mm) self->codec_id = client_info->h264_codec_id; self->in_codec_mode = 1; client_info->capture_code = 3; - client_info->capture_format = - /* XRDP_nv12 */ - (12 << 24) | (64 << 16) | (0 << 12) | (0 << 8) | (0 << 4) | 0; + client_info->capture_format = XRDP_nv12; self->process_enc = process_enc_h264; } else @@ -131,7 +161,9 @@ xrdp_encoder_create(struct xrdp_mm *mm) return 0; } - LOG_DEVEL(LOG_LEVEL_INFO, "init_xrdp_encoder: initializing encoder codec_id %d", self->codec_id); + LOG_DEVEL(LOG_LEVEL_INFO, + "init_xrdp_encoder: initializing encoder codec_id %d", + self->codec_id); /* setup required FIFOs */ self->fifo_to_proc = fifo_create(xrdp_enc_data_destructor); @@ -146,8 +178,17 @@ xrdp_encoder_create(struct xrdp_mm *mm) self->xrdp_encoder_event_processed = g_create_wait_obj(buf); g_snprintf(buf, 1024, "xrdp_%8.8x_encoder_term", pid); self->xrdp_encoder_term = g_create_wait_obj(buf); - self->max_compressed_bytes = client_info->max_fastpath_frag_bytes & ~15; - self->frames_in_flight = client_info->max_unacknowledged_frame_count; + if (client_info->gfx) + { + // Magic numbers... Why? + self->frames_in_flight = 2; + self->max_compressed_bytes = 3145728; + } + else + { + self->frames_in_flight = client_info->max_unacknowledged_frame_count; + self->max_compressed_bytes = client_info->max_fastpath_frag_bytes & ~15; + } /* make sure frames_in_flight is at least 1 */ self->frames_in_flight = MAX(self->frames_in_flight, 1); @@ -354,9 +395,9 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) tiles[index].y = y; tiles[index].cx = cx; tiles[index].cy = cy; - tiles[index].quant_y = 0; - tiles[index].quant_cb = 0; - tiles[index].quant_cr = 0; + tiles[index].quant_y = self->quant_idx_y; + tiles[index].quant_cb = self->quant_idx_u; + tiles[index].quant_cr = self->quant_idx_v; } count = enc->num_drects; @@ -376,9 +417,11 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) tiles_written = rfxcodec_encode(self->codec_handle, out_data + XRDP_SURCMD_PREFIX_BYTES, &out_data_bytes, enc->data, - enc->width, enc->height, enc->width * 4, + enc->width, enc->height, + enc->width * 4, rfxrects, enc->num_drects, - tiles, tiles_left, 0, 0); + tiles, enc->num_crects, + self->quants, self->num_quants); } } @@ -399,7 +442,11 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) enc_done->enc = enc; enc_done->cx = self->mm->wm->screen->width; enc_done->cy = self->mm->wm->screen->height; - + if (self->gfx) + { + enc_done->flags = (enum xrdp_encoder_flags) + ((int)enc_done->flags | GFX_PROGRESSIVE_RFX); + } enc_done->continuation = all_tiles_written > 0; if (tiles_written > 0) { @@ -429,7 +476,7 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) static int process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) { - LOG_DEVEL(LOG_LEVEL_INFO, "process_enc_x264:"); + LOG_DEVEL(LOG_LEVEL_INFO, "process_enc_h264: dummy func"); return 0; } diff --git a/xrdp/xrdp_encoder.h b/xrdp/xrdp_encoder.h index 59bebaa8..a5c32a58 100644 --- a/xrdp/xrdp_encoder.h +++ b/xrdp/xrdp_encoder.h @@ -3,6 +3,7 @@ #define _XRDP_ENCODER_H #include "arch.h" +#include "xrdp_client_info.h" struct fifo; struct xrdp_enc_data; @@ -27,6 +28,13 @@ struct xrdp_encoder int frame_id_server; /* last frame id received from Xorg */ int frame_id_server_sent; int frames_in_flight; + int gfx; + int gfx_ack_off; + const char *quants; + int num_quants; + int quant_idx_y; + int quant_idx_u; + int quant_idx_v; }; /* used when scheduling tasks in xrdp_encoder.c */ @@ -63,6 +71,7 @@ struct xrdp_enc_data_done int y; int cx; int cy; + enum xrdp_encoder_flags flags; }; typedef struct xrdp_enc_data_done XRDP_ENC_DATA_DONE; diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index ccade62a..8769a61d 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -79,7 +79,13 @@ xrdp_mm_create(struct xrdp_wm *owner) self->wm->client_info->rfx_codec_id, self->wm->client_info->h264_codec_id); - self->encoder = xrdp_encoder_create(self); + if ((self->wm->client_info->gfx == 0) && + ((self->wm->client_info->h264_codec_id != 0) || + (self->wm->client_info->jpeg_codec_id != 0) || + (self->wm->client_info->rfx_codec_id != 0))) + { + self->encoder = xrdp_encoder_create(self); + } return self; } diff --git a/xrdp/xrdp_painter.c b/xrdp/xrdp_painter.c index 50ab371a..fce0d378 100644 --- a/xrdp/xrdp_painter.c +++ b/xrdp/xrdp_painter.c @@ -93,35 +93,54 @@ xrdp_painter_send_dirty(struct xrdp_painter *self) Bpp = 4; } - jndex = 0; - error = xrdp_region_get_rect(self->dirty_region, jndex, &rect); - while (error == 0) + if (self->session->client_info->gfx) { - cx = rect.right - rect.left; - cy = rect.bottom - rect.top; - ldata = (char *)g_malloc(cx * cy * Bpp, 0); - if (ldata == 0) + if (self->wm->screen_dirty_region == NULL) { - return 1; + self->wm->screen_dirty_region = xrdp_region_create(self->wm); } - src = self->wm->screen->data; - src += self->wm->screen->line_size * rect.top; - src += rect.left * Bpp; - dst = ldata; - for (index = 0; index < cy; index++) - { - g_memcpy(dst, src, cx * Bpp); - src += self->wm->screen->line_size; - dst += cx * Bpp; - } - LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_painter_send_dirty: x %d y %d cx %d cy %d", - rect.left, rect.top, cx, cy); - libxrdp_send_bitmap(self->session, cx, cy, bpp, - ldata, rect.left, rect.top, cx, cy); - g_free(ldata); - - jndex++; + jndex = 0; error = xrdp_region_get_rect(self->dirty_region, jndex, &rect); + while (error == 0) + { + xrdp_region_add_rect(self->wm->screen_dirty_region, &rect); + jndex++; + error = xrdp_region_get_rect(self->dirty_region, jndex, &rect); + } + } + else + { + jndex = 0; + error = xrdp_region_get_rect(self->dirty_region, jndex, &rect); + while (error == 0) + { + cx = rect.right - rect.left; + cy = rect.bottom - rect.top; + ldata = (char *)g_malloc(cx * cy * Bpp, 0); + if (ldata == 0) + { + return 1; + } + src = self->wm->screen->data; + src += self->wm->screen->line_size * rect.top; + src += rect.left * Bpp; + dst = ldata; + for (index = 0; index < cy; index++) + { + g_memcpy(dst, src, cx * Bpp); + src += self->wm->screen->line_size; + dst += cx * Bpp; + } + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_painter_send_dirty:" + " x %d y %d cx %d cy %d", + rect.left, rect.top, cx, cy); + libxrdp_send_bitmap(self->session, cx, cy, bpp, + ldata, rect.left, rect.top, cx, cy); + g_free(ldata); + + jndex++; + error = xrdp_region_get_rect(self->dirty_region, jndex, &rect); + } } xrdp_region_delete(self->dirty_region); @@ -145,8 +164,8 @@ xrdp_painter_create(struct xrdp_wm *wm, struct xrdp_session *session) self->rop = 0xcc; /* copy will use 0xcc */ self->clip_children = 1; - - if (self->session->client_info->no_orders_supported) + if (self->session->client_info->no_orders_supported || + self->session->client_info->gfx) { #if defined(XRDP_PAINTER) if (painter_create(&(self->painter)) != PT_ERROR_NONE) diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 5f8a7300..d0bce057 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -374,6 +374,13 @@ enum display_resize_state "unknown" \ ) +enum xrdp_egfx_flags +{ + XRDP_EGFX_NONE = 0, + XRDP_EGFX_H264 = 1, + XRDP_EGFX_RFX_PRO = 2 +}; + struct xrdp_mm { struct xrdp_wm *wm; /* owner */ @@ -410,7 +417,8 @@ struct xrdp_mm int dynamic_monitor_chanid; struct xrdp_egfx *egfx; int egfx_up; - + int egfx_flags; + int gfx_delay_autologin; /* Resize on-the-fly control */ struct display_control_monitor_layout_data *resize_data; struct list *resize_queue; diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index 8a34b033..8d0a48c3 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -767,10 +767,19 @@ xrdp_wm_init(struct xrdp_wm *self) list_add_strdup(self->mm->login_values, r); } - /* - * Skip the login box and go straight to the connection phase - */ - xrdp_wm_set_login_state(self, WMLS_START_CONNECT); + if (self->session->client_info->gfx && !self->mm->egfx_up) + { + /* gfx session but have not recieved caps advertise yet, + set flag so we will connect to backend later */ + self->mm->gfx_delay_autologin = 1; + } + else + { + /* + * Skip the login box and go straight to the connection phase + */ + xrdp_wm_set_login_state(self, WMLS_START_CONNECT); + } } else { From 65137e6edb6533e3c5869f95728a32b8b7f30420 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Sun, 24 Dec 2023 15:35:28 -0500 Subject: [PATCH 02/21] More integration work from mainline_merge_shm - Introduce functional EGFX caps. - Prototype of RFX Progressive working. - Update resizing to work with it. - Refactoring --- common/xrdp_client_info.h | 3 +- xrdp/xrdp.h | 3 +- xrdp/xrdp_encoder.c | 32 +- xrdp/xrdp_mm.c | 637 ++++++++++++++++++++++++++++++++------ xrdp/xrdp_types.h | 14 +- xup/xup.c | 175 +++++------ 6 files changed, 661 insertions(+), 203 deletions(-) diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index a588f16c..ad5012bb 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -222,7 +222,8 @@ enum xrdp_encoder_flags { NONE = 0, ENCODE_COMPLETE = 1 << 0, - GFX_PROGRESSIVE_RFX = 1 << 1 + GFX_PROGRESSIVE_RFX = 1 << 1, + GFX_H264 = 1 << 2 }; /* yyyymmdd of last incompatible change to xrdp_client_info */ diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 0db9f35b..ba281fa0 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -543,7 +543,8 @@ server_set_pointer_large(struct xrdp_mod *mod, int x, int y, char *data, char *mask, int bpp, int width, int height); int -server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, +server_paint_rects_ex(struct xrdp_mod *mod, + int num_drects, short *drects, int num_crects, short *crects, char *data, int left, int top, int width, int height, diff --git a/xrdp/xrdp_encoder.c b/xrdp/xrdp_encoder.c index 8c3d9d0b..f7a08674 100644 --- a/xrdp/xrdp_encoder.c +++ b/xrdp/xrdp_encoder.c @@ -33,6 +33,7 @@ #endif #define XRDP_SURCMD_PREFIX_BYTES 256 +#define OUT_DATA_BYTES_DEFAULT_SIZE (16 * 1024 * 1024) #ifdef XRDP_RFXCODEC /* LH3 LL3, HH3 HL3, HL2 LH2, LH1 HH2, HH1 HL1 todo check this */ @@ -77,6 +78,8 @@ xrdp_enc_data_done_destructor(void *item, void *closure) struct xrdp_encoder * xrdp_encoder_create(struct xrdp_mm *mm) { + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_encoder_create:"); + struct xrdp_encoder *self; struct xrdp_client_info *client_info; char buf[1024]; @@ -106,7 +109,8 @@ xrdp_encoder_create(struct xrdp_mm *mm) if (client_info->jpeg_codec_id != 0) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: starting jpeg codec session"); + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: " + "starting jpeg codec session"); self->codec_id = client_info->jpeg_codec_id; self->in_codec_mode = 1; self->codec_quality = client_info->jpeg_prop[0]; @@ -136,7 +140,8 @@ xrdp_encoder_create(struct xrdp_mm *mm) } else if (client_info->rfx_codec_id != 0) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: starting rfx codec session"); + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: " + "starting rfx codec session"); self->codec_id = client_info->rfx_codec_id; self->in_codec_mode = 1; client_info->capture_code = 2; @@ -148,7 +153,8 @@ xrdp_encoder_create(struct xrdp_mm *mm) #endif else if (client_info->h264_codec_id != 0) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: starting h264 codec session"); + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: " + "starting h264 codec session"); self->codec_id = client_info->h264_codec_id; self->in_codec_mode = 1; client_info->capture_code = 3; @@ -277,15 +283,18 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) continue; } - LOG_DEVEL(LOG_LEVEL_DEBUG, "process_enc_jpg: x %d y %d cx %d cy %d", x, y, cx, cy); + LOG_DEVEL(LOG_LEVEL_DEBUG, "process_enc_jpg: x %d y %d cx %d cy %d", + x, y, cx, cy); out_data_bytes = MAX((cx + 4) * cy * 4, 8192); - if ((out_data_bytes < 1) || (out_data_bytes > 16 * 1024 * 1024)) + if ((out_data_bytes < 1) + || (out_data_bytes > OUT_DATA_BYTES_DEFAULT_SIZE)) { LOG_DEVEL(LOG_LEVEL_ERROR, "process_enc_jpg: error 2"); return 1; } - out_data = (char *) g_malloc(out_data_bytes + 256 + 2, 0); + out_data = (char *) g_malloc(out_data_bytes + + XRDP_SURCMD_PREFIX_BYTES + 2, 0); if (out_data == 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "process_enc_jpg: error 3"); @@ -298,15 +307,18 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) enc->width, enc->height, enc->width * 4, x, y, cx, cy, quality, - out_data + 256 + 2, &out_data_bytes); + out_data + + XRDP_SURCMD_PREFIX_BYTES + 2, + &out_data_bytes); if (error < 0) { - LOG_DEVEL(LOG_LEVEL_ERROR, "process_enc_jpg: jpeg error %d bytes %d", - error, out_data_bytes); + LOG_DEVEL(LOG_LEVEL_ERROR, "process_enc_jpg: jpeg error %d " + "bytes %d", error, out_data_bytes); g_free(out_data); return 1; } - LOG_DEVEL(LOG_LEVEL_WARNING, "jpeg error %d bytes %d", error, out_data_bytes); + LOG_DEVEL(LOG_LEVEL_WARNING, + "jpeg error %d bytes %d", error, out_data_bytes); enc_done = (XRDP_ENC_DATA_DONE *) g_malloc(sizeof(XRDP_ENC_DATA_DONE), 1); enc_done->comp_bytes = out_data_bytes + 2; diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 8769a61d..78a8d95c 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -27,17 +27,15 @@ #include "guid.h" #include "ms-rdpedisp.h" #include "ms-rdpbcgr.h" - #include "scp.h" - #include - #include "xrdp_encoder.h" #include "xrdp_sockets.h" #include "xrdp_egfx.h" +#include "libxrdp.h" +#include "xrdp_channel.h" #include - /* Forward declarations */ static int xrdp_mm_chansrv_connect(struct xrdp_mm *self, const char *port); @@ -49,8 +47,6 @@ struct xrdp_mm * xrdp_mm_create(struct xrdp_wm *owner) { struct xrdp_mm *self; - char buf[1024]; - int pid; self = (struct xrdp_mm *)g_malloc(sizeof(struct xrdp_mm), 1); self->wm = owner; @@ -58,17 +54,9 @@ xrdp_mm_create(struct xrdp_wm *owner) self->login_names->auto_free = 1; self->login_values = list_create(); self->login_values->auto_free = 1; - self->resize_queue = list_create(); - self->resize_queue->auto_free = 1; self->uid = -1; /* Never good to default UIDs to 0 */ - pid = g_getpid(); - /* setup wait objects for signalling */ - g_snprintf(buf, sizeof(buf), "xrdp_%8.8x_resize_ready", pid); - self->resize_ready = g_create_wait_obj(buf); - self->resize_data = NULL; - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_create: bpp %d mcs_connection_type %d " "jpeg_codec_id %d v3_codec_id %d rfx_codec_id %d " "h264_codec_id %d", @@ -170,6 +158,7 @@ xrdp_mm_delete(struct xrdp_mm *self) list_delete(self->resize_queue); g_free(self->resize_data); g_delete_wait_obj(self->resize_ready); + xrdp_egfx_shutdown_full(self->egfx); g_free(self); } @@ -1090,6 +1079,30 @@ xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, return 0; } +/******************************************************************************/ +static int +xrdp_mm_egfx_invalidate_all(struct xrdp_mm *self) +{ + struct xrdp_rect xr_rect; + struct xrdp_bitmap *screen; + int error; + + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_invalidate_all:"); + + screen = self->wm->screen; + + xr_rect.left = 0; + xr_rect.top = 0; + xr_rect.right = screen->width; + xr_rect.bottom = screen->height; + if (self->wm->screen_dirty_region == NULL) + { + self->wm->screen_dirty_region = xrdp_region_create(self->wm); + } + error = xrdp_region_add_rect(self->wm->screen_dirty_region, &xr_rect); + return error; +} + /******************************************************************************/ static int dynamic_monitor_open_response(intptr_t id, int chan_id, int creation_status) @@ -1139,6 +1152,265 @@ dynamic_monitor_data_first(intptr_t id, int chan_id, char *data, int bytes, return 0; } +/******************************************************************************/ +int +advance_resize_state_machine(struct xrdp_mm *mm, + enum display_resize_state new_state) +{ + struct display_control_monitor_layout_data *description = mm->resize_data; + LOG_DEVEL(LOG_LEVEL_INFO, + "advance_resize_state_machine:" + " Processing resize to: %d x %d." + " Advancing state from %s to %s." + " Previous state took %d MS.", + description->description.session_width, + description->description.session_height, + XRDP_DISPLAY_RESIZE_STATE_TO_STR(description->state), + XRDP_DISPLAY_RESIZE_STATE_TO_STR(new_state), + g_time3() - description->last_state_update_timestamp); + description->state = new_state; + description->last_state_update_timestamp = g_time3(); + g_set_wait_obj(mm->resize_ready); + return 0; +} + +/******************************************************************************/ +static int +xrdp_mm_egfx_caps_advertise(void *user, int caps_count, + int *versions, int *flagss) +{ + struct xrdp_mm *self; + struct xrdp_bitmap *screen; + int index; + int best_index; + int best_h264_index; + int best_pro_index; + int error; + int version; + int flags; + + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise:"); + self = (struct xrdp_mm *) user; + screen = self->wm->screen; + if (screen->data == NULL) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: can not do gfx"); + } + best_index = -1; + best_h264_index = -1; + best_pro_index = -1; + for (index = 0; index < caps_count; index++) + { + version = versions[index]; + flags = flagss[index]; + LOG(LOG_LEVEL_INFO, " version 0x%8.8x flags 0x%8.8x (index: %d)", + version, flags, index); + switch (version) + { + case XR_RDPGFX_CAPVERSION_8: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_81: + if (flags & XR_RDPGFX_CAPS_FLAG_AVC420_ENABLED) + { + best_h264_index = index; + } + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_10: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_101: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_102: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_103: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_104: + if (!(flags & XR_RDPGFX_CAPS_FLAG_AVC_DISABLED)) + { + best_h264_index = index; + } + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_105: + best_pro_index = index; + break; + case XR_RDPGFX_CAPVERSION_106: + best_pro_index = index; + break; + } + } + if (best_pro_index >= 0) + { + best_index = best_pro_index; + self->egfx_flags = XRDP_EGFX_RFX_PRO; + } + /* prefer h264, todo use setting in xrdp.ini for this */ + if (best_h264_index >= 0) + { +#if defined(XRDP_X264) || defined(XRDP_NVENC) + best_index = best_h264_index; + self->egfx_flags = XRDP_EGFX_H264; +#endif + } + if (best_index >= 0) + { + LOG(LOG_LEVEL_INFO, " replying version 0x%8.8x flags 0x%8.8x", + versions[best_index], flagss[best_index]); + error = xrdp_egfx_send_capsconfirm(self->egfx, + versions[best_index], + flagss[best_index]); + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_capsconfirm " + "error %d best_index %d", error, best_index); + error = xrdp_egfx_send_reset_graphics(self->egfx, + screen->width, screen->height, + self->wm->client_info->display_sizes.monitorCount, + self->wm->client_info->display_sizes.minfo_wm); + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_reset_graphics " + "error %d monitorCount %d", + error, self->wm->client_info->display_sizes.monitorCount); + self->egfx_up = 1; + xrdp_egfx_send_create_surface(self->egfx, self->egfx->surface_id, + screen->width, screen->height, + XR_PIXEL_FORMAT_XRGB_8888); + xrdp_egfx_send_map_surface(self->egfx, self->egfx->surface_id, 0, 0); + self->encoder = xrdp_encoder_create(self); + xrdp_mm_egfx_invalidate_all(self); + + if (self->resize_data != NULL + && self->resize_data->state == WMRZ_EGFX_INITALIZING) + { + advance_resize_state_machine(self, WMRZ_EGFX_INITIALIZED); + } + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: egfx created."); + if (self->gfx_delay_autologin) + { + self->gfx_delay_autologin = 0; + xrdp_wm_set_login_state(self->wm, WMLS_START_CONNECT); + } + } + else + { + struct xrdp_rect lrect; + + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: no good gfx, canceling"); + lrect.left = 0; + lrect.top = 0; + lrect.right = screen->width; + lrect.bottom = screen->height; + self->wm->client_info->gfx = 0; + xrdp_encoder_delete(self->encoder); + self->encoder = xrdp_encoder_create(self); + xrdp_bitmap_invalidate(screen, &lrect); + } + return 0; +} + +/*****************************************************************************/ +static int +xrdp_mm_update_module_frame_ack(struct xrdp_mm *self) +{ + int fif; + struct xrdp_encoder *encoder; + + encoder = self->encoder; + fif = encoder->frames_in_flight; + if (encoder->frame_id_client + fif > encoder->frame_id_server) + { + if (encoder->frame_id_server > encoder->frame_id_server_sent) + { + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_update_module_ack: " + "frame_id_server %d", encoder->frame_id_server); + encoder->frame_id_server_sent = encoder->frame_id_server; + self->mod->mod_frame_ack(self->mod, 0, encoder->frame_id_server); + } + } + return 0; +} + +static int +xrdp_mm_egfx_frame_ack(void *user, uint32_t queue_depth, int frame_id, + int frames_decoded) +{ + struct xrdp_mm *self; + struct xrdp_encoder *encoder; + + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_frame_ack:"); + self = (struct xrdp_mm *) user; + encoder = self->encoder; + if (encoder == NULL) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_frame_ack: encoder is nil"); + return 0; + } + if (queue_depth == XR_SUSPEND_FRAME_ACKNOWLEDGEMENT) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_frame_ack: " + "queue_depth %d frame_id %d frames_decoded %d", + queue_depth, frame_id, frames_decoded); + if (encoder->gfx_ack_off == 0) + { + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_frame_ack: " + "client request turn off frame acks."); + encoder->gfx_ack_off = 1; + frame_id = -1; + } + } + else + { + if (encoder->gfx_ack_off) + { + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_frame_ack: " + "client request turn on frame acks"); + encoder->gfx_ack_off = 0; + } + } + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_frame_ack: " + "incoming %d, client %d, server %d", + frame_id, encoder->frame_id_client, encoder->frame_id_server); + if (frame_id < 0 || frame_id > encoder->frame_id_server) + { + /* if frame_id is negative or bigger then what server last sent + just ack all sent frames */ + /* some clients can send big number just to clear all + pending frames */ + encoder->frame_id_client = encoder->frame_id_server; + } + else + { + /* frame acks can come out of order so ignore older one */ + encoder->frame_id_client = MAX(frame_id, encoder->frame_id_client); + } + xrdp_mm_update_module_frame_ack(self); + return 0; +} + +/******************************************************************************/ +int +egfx_initialize(struct xrdp_mm *self) +{ + LOG_DEVEL(LOG_LEVEL_TRACE, "egfx_initialize"); + if (!(self->wm->client_info->mcs_early_capability_flags + & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL)) + { + return 0; + } + LOG_DEVEL(LOG_LEVEL_INFO, "egfx_initialize: gfx capable client"); + if (xrdp_egfx_create(self, &(self->egfx)) == 0) + { + self->egfx->user = self; + self->egfx->caps_advertise = xrdp_mm_egfx_caps_advertise; + self->egfx->frame_ack = xrdp_mm_egfx_frame_ack; + return 0; + } + LOG_DEVEL(LOG_LEVEL_INFO, "egfx_initialize: xrdp_egfx_create failed"); + return 1; +} + /******************************************************************************/ static const int MAXIMUM_MONITOR_SIZE = sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS; @@ -1162,27 +1434,6 @@ sync_dynamic_monitor_data(struct xrdp_wm *wm, MAXIMUM_MONITOR_SIZE); } -int -advance_resize_state_machine(struct xrdp_mm *mm, - enum display_resize_state new_state) -{ - struct display_control_monitor_layout_data *description = mm->resize_data; - LOG_DEVEL(LOG_LEVEL_INFO, - "advance_resize_state_machine:" - " Processing resize to: %d x %d." - " Advancing state from %s to %s." - " Previous state took %d MS.", - description->description.session_width, - description->description.session_height, - XRDP_DISPLAY_RESIZE_STATE_TO_STR(description->state), - XRDP_DISPLAY_RESIZE_STATE_TO_STR(new_state), - g_time3() - description->last_state_update_timestamp); - description->state = new_state; - description->last_state_update_timestamp = g_time3(); - g_set_wait_obj(mm->resize_ready); - return 0; -} - /******************************************************************************/ static int dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes) @@ -1269,7 +1520,8 @@ dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes) list_add_item(wm->mm->resize_queue, (tintptr)display_size_data); g_set_wait_obj(wm->mm->resize_ready); LOG(LOG_LEVEL_DEBUG, "dynamic_monitor_data:" - " received width %d, received height %d.", display_size_data->session_width, display_size_data->session_height); + " received width %d, received height %d.", + display_size_data->session_width, display_size_data->session_height); return 0; } @@ -1289,6 +1541,9 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) int error = 0; struct xrdp_mm *mm; struct xrdp_mod *module; + struct xrdp_rdp *rdp; + struct xrdp_sec *sec; + struct xrdp_channel *chan; LOG_DEVEL(LOG_LEVEL_TRACE, "process_display_control_monitor_layout_data:"); @@ -1326,6 +1581,56 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) xrdp_encoder_delete(mm->encoder); mm->encoder = NULL; } + if (mm->egfx == 0) + { + advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE); + } + else + { + advance_resize_state_machine(mm, WMRZ_EGFX_DELETE_SURFACE); + } + break; + case WMRZ_EGFX_DELETE_SURFACE: + if (error == 0 && module != 0) + { + xrdp_egfx_shutdown_delete_surface(mm->egfx); + } + advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSE); + break; + case WMRZ_EGFX_CONN_CLOSE: + if (error == 0 && module != 0) + { + xrdp_egfx_shutdown_close_connection(wm->mm->egfx); + } + advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSING); + break; + // Also processed in xrdp_egfx_close_response + case WMRZ_EGFX_CONN_CLOSING: + rdp = (struct xrdp_rdp *) (mm->wm->session->rdp); + sec = rdp->sec_layer; + chan = sec->chan_layer; + + // Continue to check to see if the connection is closed. If it + // ever is, advance the state machine! + if (chan->drdynvcs[mm->egfx->channel_id].status + == XRDP_DRDYNVC_STATUS_CLOSED + || (g_time3() - description->last_state_update_timestamp) > 100) + { + advance_resize_state_machine(mm, WMRZ_EGFX_CONN_CLOSED); + break; + } + g_set_wait_obj(mm->resize_ready); + break; + case WMRZ_EGFX_CONN_CLOSED: + advance_resize_state_machine(mm, WRMZ_EGFX_DELETE); + break; + case WRMZ_EGFX_DELETE: + if (error == 0 && module != 0) + { + xrdp_egfx_shutdown_delete(wm->mm->egfx); + mm->egfx = NULL; + mm->egfx_up = 0; + } advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE); break; case WMRZ_SERVER_MONITOR_RESIZE: @@ -1338,9 +1643,10 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) " mod_server_monitor_resize failed %d", error); return advance_error(error, mm); } - advance_resize_state_machine(mm, WMRZ_SERVER_VERSION_MESSAGE); + advance_resize_state_machine( + mm, WMRZ_SERVER_VERSION_MESSAGE_START); break; - case WMRZ_SERVER_VERSION_MESSAGE: + case WMRZ_SERVER_VERSION_MESSAGE_START: error = module->mod_server_version_message(module); if (error != 0) { @@ -1349,6 +1655,12 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) " mod_server_version_message failed %d", error); return advance_error(error, mm); } + advance_resize_state_machine( + mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING); + break; + // Not processed here. Processed in server_reset + // case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING: + case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED: advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESIZE); break; case WMRZ_XRDP_CORE_RESIZE: @@ -1400,6 +1712,22 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) return advance_error(error, mm); } sync_dynamic_monitor_data(wm, &(description->description)); + advance_resize_state_machine(mm, WMRZ_EGFX_INITIALIZE); + break; + case WMRZ_EGFX_INITIALIZE: + if (error == 0 && mm->egfx == NULL && mm->egfx_up == 0) + { + egfx_initialize(mm); + advance_resize_state_machine(mm, WMRZ_EGFX_INITALIZING); + } + else + { + advance_resize_state_machine(mm, WMRZ_EGFX_INITIALIZED); + } + break; + // Not processed here. Processed in xrdp_mm_egfx_caps_advertise + // case WMRZ_EGFX_INITALIZING: + case WMRZ_EGFX_INITIALIZED: advance_resize_state_machine(mm, WMRZ_ENCODER_CREATE); break; case WMRZ_ENCODER_CREATE: @@ -1450,7 +1778,7 @@ dynamic_monitor_process_queue(struct xrdp_mm *self) return 0; } - if (self->resize_data == NULL) + if (self->resize_data == NULL && self->resize_queue != NULL) { if (self->resize_queue->count <= 0) { @@ -1518,6 +1846,11 @@ dynamic_monitor_process_queue(struct xrdp_mm *self) " Resize data is not null."); } + if (self->resize_data == NULL) + { + return 0; + } + if (self->resize_data->state == WMRZ_COMPLETE) { LOG(LOG_LEVEL_INFO, "dynamic_monitor_process_queue: Clearing" @@ -1552,6 +1885,8 @@ dynamic_monitor_initialize(struct xrdp_mm *self) struct xrdp_drdynvc_procs d_procs; int flags; int error; + char buf[1024]; + int pid; LOG_DEVEL(LOG_LEVEL_TRACE, "dynamic_monitor_initialize:"); @@ -1567,9 +1902,20 @@ dynamic_monitor_initialize(struct xrdp_mm *self) &(self->dynamic_monitor_chanid)); if (error != 0) { - LOG(LOG_LEVEL_ERROR, "xrdp_mm_drdynvc_up: " + LOG(LOG_LEVEL_ERROR, "dynamic_monitor_initialize: " "libxrdp_drdynvc_open failed %d", error); + return error; } + + // Initialize xrdp_mm specific variables. + self->resize_queue = list_create(); + self->resize_queue->auto_free = 1; + pid = g_getpid(); + /* setup wait objects for signaling */ + g_snprintf(buf, sizeof(buf), "xrdp_%8.8x_resize_ready", pid); + self->resize_ready = g_create_wait_obj(buf); + self->resize_data = NULL; + return error; } @@ -1583,6 +1929,12 @@ xrdp_mm_drdynvc_up(struct xrdp_mm *self) LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_drdynvc_up:"); + error = egfx_initialize(self); + if (error != 0) + { + return error; + } + enable_dynamic_resize = xrdp_mm_get_value(self, "enable_dynamic_resizing"); /* * User can disable dynamic resizing if necessary @@ -1593,10 +1945,17 @@ xrdp_mm_drdynvc_up(struct xrdp_mm *self) LOG(LOG_LEVEL_INFO, "User has disabled dynamic resizing."); return error; } - ignore_marker = (struct display_control_monitor_layout_data *) - g_malloc(sizeof(struct display_control_monitor_layout_data), 1); - list_add_item(self->resize_queue, (tintptr)ignore_marker); error = dynamic_monitor_initialize(self); + if (error != 0) + { + LOG(LOG_LEVEL_INFO, "Dynamic monitor initialize failed." + " Client likely does not support it."); + return error; + } + ignore_marker = (struct display_control_monitor_layout_data *) + g_malloc(sizeof(struct display_control_monitor_layout_data), + 1); + list_add_item(self->resize_queue, (tintptr)ignore_marker); return error; } @@ -2795,7 +3154,10 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) } } - +#define MIN_MS_BETWEEN_FRAMES 40 +/* can not change this to zero yet, g_obj_wait in os_calls.c treats + everything less then 1 to mean wait forever */ +#define MIN_MS_TO_WAIT_FOR_MORE_UPDATES 1 /*****************************************************************************/ int xrdp_mm_get_wait_objs(struct xrdp_mm *self, @@ -2842,6 +3204,25 @@ xrdp_mm_get_wait_objs(struct xrdp_mm *self, read_objs[(*rcount)++] = self->resize_ready; } + if (self->wm->screen_dirty_region != NULL) + { + if (xrdp_region_not_empty(self->wm->screen_dirty_region)) + { + int now = g_time3(); + int next_screen_draw_time = self->wm->last_screen_draw_time + + MIN_MS_BETWEEN_FRAMES; + int diff = next_screen_draw_time - now; + int ltimeout = *timeout; + diff = MAX(diff, MIN_MS_TO_WAIT_FOR_MORE_UPDATES); + diff = MIN(diff, MIN_MS_BETWEEN_FRAMES); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_get_wait_objs:" + " not empty diff %d", diff); + if ((ltimeout < 0) || (ltimeout > diff)) + { + *timeout = diff; + } + } + } return rv; } @@ -2919,28 +3300,6 @@ xrdp_mm_check_chan(struct xrdp_mm *self) return 0; } -/*****************************************************************************/ -static int -xrdp_mm_update_module_frame_ack(struct xrdp_mm *self) -{ - int fif; - struct xrdp_encoder *encoder; - - encoder = self->encoder; - fif = encoder->frames_in_flight; - if (encoder->frame_id_client + fif > encoder->frame_id_server) - { - if (encoder->frame_id_server > encoder->frame_id_server_sent) - { - LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_update_module_ack: frame_id_server %d", - encoder->frame_id_server); - encoder->frame_id_server_sent = encoder->frame_id_server; - self->mod->mod_frame_ack(self->mod, 0, encoder->frame_id_server); - } - } - return 0; -} - /*****************************************************************************/ static int xrdp_mm_process_enc_done(struct xrdp_mm *self) @@ -2973,22 +3332,45 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) cy = enc_done->cy; if (enc_done->comp_bytes > 0) { - if (!enc_done->continuation) + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_process_enc_done: " + "x %d y %d cx %d cy %d frame_id %d use_frame_acks %d", + x, y, cx, cy, enc_done->enc->frame_id, + self->wm->client_info->use_frame_acks); + if (enc_done->flags & GFX_H264) { - libxrdp_fastpath_send_frame_marker(self->wm->session, 0, - enc_done->enc->frame_id); + LOG(LOG_LEVEL_INFO, "GFX H264 Unimplemeted."); } - libxrdp_fastpath_send_surface(self->wm->session, - enc_done->comp_pad_data, - enc_done->pad_bytes, - enc_done->comp_bytes, - x, y, x + cx, y + cy, - 32, self->encoder->codec_id, - cx, cy); - if (enc_done->last) + else if (enc_done->flags & GFX_PROGRESSIVE_RFX) /* gfx progressive rfx */ { - libxrdp_fastpath_send_frame_marker(self->wm->session, 1, - enc_done->enc->frame_id); + xrdp_egfx_send_frame_start(self->egfx, + enc_done->enc->frame_id, 0); + xrdp_egfx_send_wire_to_surface2(self->egfx, + self->egfx->surface_id, 9, 1, + XR_PIXEL_FORMAT_XRGB_8888, + enc_done->comp_pad_data + + enc_done->pad_bytes, + enc_done->comp_bytes); + xrdp_egfx_send_frame_end(self->egfx, enc_done->enc->frame_id); + } + else + { + if (!enc_done->continuation) + { + libxrdp_fastpath_send_frame_marker(self->wm->session, 0, + enc_done->enc->frame_id); + } + libxrdp_fastpath_send_surface(self->wm->session, + enc_done->comp_pad_data, + enc_done->pad_bytes, + enc_done->comp_bytes, + x, y, x + cx, y + cy, + 32, self->encoder->codec_id, + cx, cy); + if (enc_done->last) + { + libxrdp_fastpath_send_frame_marker(self->wm->session, 1, + enc_done->enc->frame_id); + } } } /* free enc_done */ @@ -2996,16 +3378,35 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) { enc = enc_done->enc; LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_process_enc_done: last set"); - if (self->wm->client_info->use_frame_acks == 0) + if (enc_done->flags & GFX_H264) /* gfx */ { - self->mod->mod_frame_ack(self->mod, - enc->flags, - enc->frame_id); + if (self->encoder->gfx_ack_off) + { + /* gfx and client turned off client frame acks */ + self->mod->mod_frame_ack(self->mod, + enc->flags, + enc->frame_id); + } + else + { + self->encoder->frame_id_server = enc->frame_id; + xrdp_mm_update_module_frame_ack(self); + } } else { - self->encoder->frame_id_server = enc->frame_id; - xrdp_mm_update_module_frame_ack(self); + if (self->wm->client_info->use_frame_acks == 0) + { + /* surface commmand and client does not do frame acks */ + self->mod->mod_frame_ack(self->mod, + enc->flags, + enc->frame_id); + } + else + { + self->encoder->frame_id_server = enc_done->enc->frame_id; + xrdp_mm_update_module_frame_ack(self); + } } g_free(enc->drects); g_free(enc->crects); @@ -3143,8 +3544,9 @@ xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id) return 1; } encoder = self->encoder; - LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_frame_ack: incoming %d, client %d, server %d", - frame_id, encoder->frame_id_client, encoder->frame_id_server); + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_frame_ack: " + "incoming %d, client %d, server %d", frame_id, + encoder->frame_id_client, encoder->frame_id_server); if ((frame_id < 0) || (frame_id > encoder->frame_id_server)) { /* if frame_id is negative or bigger then what server last sent @@ -3389,9 +3791,11 @@ server_paint_rects(struct xrdp_mod *mod, int num_drects, short *drects, /*****************************************************************************/ int -server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, - int num_crects, short *crects, char *data, - int left, int top, int width, int height, +server_paint_rects_ex(struct xrdp_mod *mod, + int num_drects, short *drects, + int num_crects, short *crects, + char *data, int left, int top, + int width, int height, int flags, int frame_id, void *shmem_ptr, int shmem_bytes) { @@ -3406,7 +3810,7 @@ server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, wm = (struct xrdp_wm *)(mod->wm); mm = wm->mm; - LOG_DEVEL(LOG_LEVEL_DEBUG, "server_paint_rects: %p", mm->encoder); + LOG(LOG_LEVEL_TRACE, "server_paint_rects_ex: %p", mm->encoder); if (mm->encoder != 0) { @@ -3477,7 +3881,12 @@ server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, return 0; } - LOG(LOG_LEVEL_TRACE, "server_paint_rects:"); + if (wm->client_info->gfx) + { + LOG(LOG_LEVEL_DEBUG, "server_paint_rects: gfx session and no encoder"); + mm->mod->mod_frame_ack(mm->mod, flags, frame_id); + return 0; + } p = (struct xrdp_painter *)(mod->painter); if (p == 0) @@ -3796,8 +4205,16 @@ int server_reset(struct xrdp_mod *mod, int width, int height, int bpp) { struct xrdp_wm *wm; + struct xrdp_mm *mm; + + LOG(LOG_LEVEL_TRACE, "server_reset:"); wm = (struct xrdp_wm *)(mod->wm); + if (wm == 0) + { + return 1; + } + mm = wm->mm; if (wm->client_info == 0) { @@ -3810,6 +4227,42 @@ server_reset(struct xrdp_mod *mod, int width, int height, int bpp) return 0; } + // bpp of zero is impossible. + // This is a signal from xup that + // It is finished resizing. + if (bpp == 0) + { + if (mm == 0) + { + return 1; + } + if (!xrdp_wm_can_resize(wm)) + { + return 1; + } + if (mm->resize_data == NULL) + { + mm->mod->mod_server_monitor_full_invalidate(mm->mod, width, height); + return 0; + } + if (mm->resize_data != NULL + && mm->resize_data->state + == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING) + { + LOG(LOG_LEVEL_INFO, + "server_reset: Advancing server monitor resized."); + advance_resize_state_machine( + mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED); + } + else if (mm->resize_data != NULL + && mm->resize_data->description.session_height == 0 + && mm->resize_data->description.session_width == 0) + { + mm->mod->mod_server_monitor_full_invalidate(mm->mod, width, height); + } + return 0; + } + /* if same (and only one monitor on client) don't need to do anything */ if (wm->client_info->display_sizes.session_width == (uint32_t)width && wm->client_info->display_sizes.session_height == (uint32_t)height && diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index d0bce057..06ccf446 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -28,6 +28,7 @@ #include "xrdp_constants.h" #include "fifo.h" #include "guid.h" +#include "xrdp_client_info.h" #define MAX_NR_CHANNELS 16 #define MAX_CHANNEL_NAME 16 @@ -343,7 +344,9 @@ enum display_resize_state WMRZ_EGFX_CONN_CLOSED, WRMZ_EGFX_DELETE, WMRZ_SERVER_MONITOR_RESIZE, - WMRZ_SERVER_VERSION_MESSAGE, + WMRZ_SERVER_VERSION_MESSAGE_START, + WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING, + WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED, WMRZ_XRDP_CORE_RESIZE, WMRZ_EGFX_INITIALIZE, WMRZ_EGFX_INITALIZING, @@ -362,7 +365,12 @@ enum display_resize_state (status) == WMRZ_EGFX_CONN_CLOSED ? "WMRZ_EGFX_CONN_CLOSED" : \ (status) == WRMZ_EGFX_DELETE ? "WMRZ_EGFX_DELETE" : \ (status) == WMRZ_SERVER_MONITOR_RESIZE ? "WMRZ_SERVER_MONITOR_RESIZE" : \ - (status) == WMRZ_SERVER_VERSION_MESSAGE ? "WMRZ_SERVER_VERSION_MESSAGE" : \ + (status) == WMRZ_SERVER_VERSION_MESSAGE_START ? \ + "WMRZ_SERVER_VERSION_MESSAGE_START" : \ + (status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING ? \ + "WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING" : \ + (status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED ? \ + "WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED" : \ (status) == WMRZ_XRDP_CORE_RESIZE ? "WMRZ_XRDP_CORE_RESIZE" : \ (status) == WMRZ_EGFX_INITIALIZE ? "WMRZ_EGFX_INITIALIZE" : \ (status) == WMRZ_EGFX_INITALIZING ? "WMRZ_EGFX_INITALIZING" : \ @@ -417,7 +425,7 @@ struct xrdp_mm int dynamic_monitor_chanid; struct xrdp_egfx *egfx; int egfx_up; - int egfx_flags; + enum xrdp_egfx_flags egfx_flags; int gfx_delay_autologin; /* Resize on-the-fly control */ struct display_control_monitor_layout_data *resize_data; diff --git a/xup/xup.c b/xup/xup.c index 4215d0bc..0b6cbd04 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -1174,47 +1174,33 @@ process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s) in_uint16_le(s, height); bmpdata = 0; - if (flags == 0) /* screen */ + if (amod->screen_shmem_id_mapped == 0) { - /* Do we need to map (or remap) the memory - * area shared with the X server ? */ - if (amod->screen_shmem_id_mapped == 0 || - amod->screen_shmem_id != shmem_id) + amod->screen_shmem_id = shmem_id; + amod->screen_shmem_pixels = (char *) g_shmat(amod->screen_shmem_id); + if (amod->screen_shmem_pixels == (void *) -1) { - if (amod->screen_shmem_id_mapped != 0) - { - g_shmdt(amod->screen_shmem_pixels); - } - amod->screen_shmem_pixels = (char *) g_shmat(shmem_id); - if (amod->screen_shmem_pixels == (void *) -1) - { - /* failed */ - if (amod->screen_shmem_id_mapped == 0) - { - LOG(LOG_LEVEL_ERROR, - "Can't attach to shared memory id %d [%s]", - shmem_id, g_get_strerror()); - } - else - { - LOG(LOG_LEVEL_ERROR, - "Can't attach to shared memory id %d from id %d [%s]", - shmem_id, amod->screen_shmem_id, g_get_strerror()); - } - amod->screen_shmem_id = 0; - amod->screen_shmem_pixels = 0; - amod->screen_shmem_id_mapped = 0; - } - else - { - amod->screen_shmem_id = shmem_id; - amod->screen_shmem_id_mapped = 1; - } + /* failed */ + amod->screen_shmem_id = 0; + amod->screen_shmem_pixels = 0; + amod->screen_shmem_id_mapped = 0; } - - if (amod->screen_shmem_pixels != 0) + else { - bmpdata = amod->screen_shmem_pixels + shmem_offset; + amod->screen_shmem_id_mapped = 1; + } + } + else if (amod->screen_shmem_id != shmem_id) + { + amod->screen_shmem_id = shmem_id; + g_shmdt(amod->screen_shmem_pixels); + amod->screen_shmem_pixels = (char *) g_shmat(amod->screen_shmem_id); + if (amod->screen_shmem_pixels == (void *) -1) + { + /* failed */ + amod->screen_shmem_id = 0; + amod->screen_shmem_pixels = 0; + amod->screen_shmem_id_mapped = 0; } } else @@ -1225,7 +1211,10 @@ process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s) flags, frame_id, shmem_id, shmem_offset, width, height); } - + if (amod->screen_shmem_pixels != 0) + { + bmpdata = amod->screen_shmem_pixels + shmem_offset; + } if (bmpdata != 0) { rv = amod->server_paint_rects(amod, num_drects, ldrects, @@ -1238,9 +1227,6 @@ process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s) rv = 1; } - //LOG_DEVEL(LOG_LEVEL_TRACE, "frame_id %d", frame_id); - //send_paint_rect_ex_ack(amod, flags, frame_id); - g_free(lcrects); g_free(ldrects); @@ -1680,74 +1666,71 @@ lib_mod_process_message(struct mod *mod, struct stream *s) char *phold; LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_process_message:"); + in_uint16_le(s, type); + in_uint16_le(s, num_orders); + in_uint32_le(s, len); + LOG_DEVEL(LOG_LEVEL_DEBUG, "lib_mod_process_message: type %d", type); + rv = 0; - if (rv == 0) + if (type == 1) /* original order list */ { - in_uint16_le(s, type); - in_uint16_le(s, num_orders); - in_uint32_le(s, len); - LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_process_message: type %d", type); - - if (type == 1) /* original order list */ + for (index = 0; index < num_orders; index++) { - for (index = 0; index < num_orders; index++) - { - in_uint16_le(s, type); - rv = lib_mod_process_orders(mod, type, s); + in_uint16_le(s, type); + rv = lib_mod_process_orders(mod, type, s); - if (rv != 0) - { + if (rv != 0) + { + break; + } + } + } + else if (type == 2) /* caps */ + { + LOG_DEVEL(LOG_LEVEL_TRACE, + "lib_mod_process_message: type 2 len %d", len); + for (index = 0; index < num_orders; index++) + { + phold = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); + + switch (type) + { + default: + LOG_DEVEL(LOG_LEVEL_TRACE, + "lib_mod_process_message: unknown" + " cap type %d len %d", + type, len); break; - } } + s->p = phold + len; } - else if (type == 2) /* caps */ + lib_send_client_info(mod); + } + else if (type == 3) /* order list with len after type */ + { + LOG_DEVEL(LOG_LEVEL_INFO, + "lib_mod_process_message: type 3 len %d", len); + for (index = 0; index < num_orders; index++) { - LOG_DEVEL(LOG_LEVEL_TRACE, - "lib_mod_process_message: type 2 len %d", len); - for (index = 0; index < num_orders; index++) + phold = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); + rv = lib_mod_process_orders(mod, type, s); + + if (rv != 0) { - phold = s->p; - in_uint16_le(s, type); - in_uint16_le(s, len); - - switch (type) - { - default: - LOG_DEVEL(LOG_LEVEL_TRACE, - "lib_mod_process_message: unknown" - " cap type %d len %d", - type, len); - break; - } - - s->p = phold + len; + break; } - lib_send_client_info(mod); - } - else if (type == 3) /* order list with len after type */ - { - for (index = 0; index < num_orders; index++) - { - phold = s->p; - in_uint16_le(s, type); - in_uint16_le(s, len); - rv = lib_mod_process_orders(mod, type, s); - - if (rv != 0) - { - break; - } - - s->p = phold + len; - } - } - else - { - LOG_DEVEL(LOG_LEVEL_TRACE, "unknown type %d", type); + s->p = phold + len; } } + else + { + LOG_DEVEL(LOG_LEVEL_TRACE, "unknown type %d", type); + } return rv; } From de2c01ad1dade22e9a7af3b3a6a91ab5bdd55f90 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Sun, 7 Jan 2024 02:27:34 -0500 Subject: [PATCH 03/21] Updating quantization values to remove corruption. --- xrdp/xrdp_encoder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xrdp/xrdp_encoder.c b/xrdp/xrdp_encoder.c index f7a08674..1ab499ca 100644 --- a/xrdp/xrdp_encoder.c +++ b/xrdp/xrdp_encoder.c @@ -39,8 +39,8 @@ /* LH3 LL3, HH3 HL3, HL2 LH2, LH1 HH2, HH1 HL1 todo check this */ static const unsigned char g_rfx_quantization_values[] = { - 0x66, 0x66, 0x77, 0x88, 0x98, - 0x76, 0x77, 0x88, 0x98, 0xA9 + 0x66, 0x66, 0x77, 0x87, 0x98, + 0x76, 0x77, 0x88, 0x98, 0x99 }; #endif From 63e963daf60ef47d64b94297a2a5ef83b7f2db1e Mon Sep 17 00:00:00 2001 From: Nexarian Date: Sun, 7 Jan 2024 02:32:01 -0500 Subject: [PATCH 04/21] Switching encoder logging statements to LOG not LOG_DEVEL --- xrdp/xrdp_encoder.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/xrdp/xrdp_encoder.c b/xrdp/xrdp_encoder.c index 1ab499ca..b4840b09 100644 --- a/xrdp/xrdp_encoder.c +++ b/xrdp/xrdp_encoder.c @@ -109,8 +109,7 @@ xrdp_encoder_create(struct xrdp_mm *mm) if (client_info->jpeg_codec_id != 0) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: " - "starting jpeg codec session"); + LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting jpeg codec session"); self->codec_id = client_info->jpeg_codec_id; self->in_codec_mode = 1; self->codec_quality = client_info->jpeg_prop[0]; @@ -140,8 +139,7 @@ xrdp_encoder_create(struct xrdp_mm *mm) } else if (client_info->rfx_codec_id != 0) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: " - "starting rfx codec session"); + LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting rfx codec session"); self->codec_id = client_info->rfx_codec_id; self->in_codec_mode = 1; client_info->capture_code = 2; @@ -153,8 +151,7 @@ xrdp_encoder_create(struct xrdp_mm *mm) #endif else if (client_info->h264_codec_id != 0) { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_create: " - "starting h264 codec session"); + LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting h264 codec session"); self->codec_id = client_info->h264_codec_id; self->in_codec_mode = 1; client_info->capture_code = 3; From 584a8944901ccf2abd95212945d2e0d6a688f2f0 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Sun, 7 Jan 2024 02:53:21 -0500 Subject: [PATCH 05/21] Add 0 as valid g_obj_wait timeout instead of having it be equivalent to -1. --- common/os_calls.c | 4 ++-- common/os_calls.h | 5 ++++- sesman/chansrv/chansrv.c | 4 ++-- sesman/sesexec/sesexec.c | 2 +- xrdp/xrdp_mm.c | 4 +--- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/common/os_calls.c b/common/os_calls.c index d8062f72..60d7705f 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -1974,7 +1974,7 @@ g_obj_wait(tintptr *read_objs, int rcount, tintptr *write_objs, int wcount, handles[j++] = (HANDLE)(write_objs[i]); } - if (mstimeout < 1) + if (mstimeout < 0) { mstimeout = INFINITE; } @@ -2011,7 +2011,7 @@ g_obj_wait(tintptr *read_objs, int rcount, tintptr *write_objs, int wcount, } else { - if (mstimeout < 1) + if (mstimeout < 0) { mstimeout = -1; } diff --git a/common/os_calls.h b/common/os_calls.h index a9cf8f5d..02758e89 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -203,10 +203,13 @@ int g_delete_wait_obj(tintptr obj); * @param rcount Number of elements in read_objs * @param write_objs Array of write objects * @param rcount Number of elements in write_objs - * @param mstimeout Timeout in milliseconds. <= 0 means an infinite timeout. + * @param mstimeout Timeout in milliseconds. < 0 means an infinite timeout. * * @return 0 for success. The objects will need to be polled to * find out what is readable or writeable. + * + * An mstimeout of zero will return immediately, although + * error conditions may be checked for. */ int g_obj_wait(tintptr *read_objs, int rcount, tintptr *write_objs, int wcount, int mstimeout); diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 31daff4c..80f0a231 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -1787,7 +1787,7 @@ main(int argc, char **argv) waiters[1] = g_exec_event; waiters[2] = g_sigchld_event; - if (g_obj_wait(waiters, 3, 0, 0, 0) != 0) + if (g_obj_wait(waiters, 3, 0, 0, -1) != 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "main: error, g_obj_wait failed"); break; @@ -1814,7 +1814,7 @@ main(int argc, char **argv) while (g_thread_done_event > 0 && !g_is_wait_obj_set(g_thread_done_event)) { /* wait for thread to exit */ - if (g_obj_wait(&g_thread_done_event, 1, 0, 0, 0) != 0) + if (g_obj_wait(&g_thread_done_event, 1, 0, 0, -1) != 0) { LOG_DEVEL(LOG_LEVEL_ERROR, "main: error, g_obj_wait failed"); break; diff --git a/sesman/sesexec/sesexec.c b/sesman/sesexec/sesexec.c index 563a0695..3e9763dd 100644 --- a/sesman/sesexec/sesexec.c +++ b/sesman/sesexec/sesexec.c @@ -283,7 +283,7 @@ sesexec_main_loop(void) continue; } - if (g_obj_wait(robjs, robjs_count, NULL, 0, 0) != 0) + if (g_obj_wait(robjs, robjs_count, NULL, 0, -1) != 0) { /* should not get here */ LOG(LOG_LEVEL_WARNING, "sesexec_main_loop: " diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 78a8d95c..42faea61 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -3155,9 +3155,7 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) } #define MIN_MS_BETWEEN_FRAMES 40 -/* can not change this to zero yet, g_obj_wait in os_calls.c treats - everything less then 1 to mean wait forever */ -#define MIN_MS_TO_WAIT_FOR_MORE_UPDATES 1 +#define MIN_MS_TO_WAIT_FOR_MORE_UPDATES 0 /*****************************************************************************/ int xrdp_mm_get_wait_objs(struct xrdp_mm *self, From 1b6ca2245d43afb309b5a7f8c2288d0902bd079a Mon Sep 17 00:00:00 2001 From: Nexarian Date: Mon, 8 Jan 2024 15:01:25 -0500 Subject: [PATCH 06/21] Fix memory leak and RFX encoder notify --- xrdp/xrdp_encoder.c | 6 +++--- xrdp/xrdp_process.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/xrdp/xrdp_encoder.c b/xrdp/xrdp_encoder.c index b4840b09..c2892b76 100644 --- a/xrdp/xrdp_encoder.c +++ b/xrdp/xrdp_encoder.c @@ -470,12 +470,12 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) tc_mutex_lock(mutex); fifo_add_item(fifo_processed, enc_done); tc_mutex_unlock(mutex); - /* signal completion for main thread */ - g_set_wait_obj(event_processed); - } while (!finished); + /* signal completion for main thread */ + g_set_wait_obj(event_processed); + return 0; } #endif diff --git a/xrdp/xrdp_process.c b/xrdp/xrdp_process.c index bf0555d6..c40613dc 100644 --- a/xrdp/xrdp_process.c +++ b/xrdp/xrdp_process.c @@ -306,6 +306,8 @@ xrdp_process_main_loop(struct xrdp_process *self) } /* Run end in module */ xrdp_process_mod_end(self); + xrdp_wm_delete(self->wm); + self->wm = NULL; libxrdp_exit(self->session); self->session = 0; self->status = -1; From 5293f13f39197d16dfd93a64916fdd9d9a1bb024 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Mon, 8 Jan 2024 17:59:22 -0500 Subject: [PATCH 07/21] Fix resize-on-the-fly by processing memory allocation complete. --- xup/xup.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/xup/xup.c b/xup/xup.c index 0b6cbd04..b40b1e9e 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -1665,6 +1665,9 @@ lib_mod_process_message(struct mod *mod, struct stream *s) int type; char *phold; + int width; + int height; + LOG_DEVEL(LOG_LEVEL_TRACE, "lib_mod_process_message:"); in_uint16_le(s, type); in_uint16_le(s, num_orders); @@ -1674,7 +1677,7 @@ lib_mod_process_message(struct mod *mod, struct stream *s) rv = 0; if (type == 1) /* original order list */ { - for (index = 0; index < num_orders; index++) + for (index = 0; index < num_orders; ++index) { in_uint16_le(s, type); rv = lib_mod_process_orders(mod, type, s); @@ -1727,6 +1730,29 @@ lib_mod_process_message(struct mod *mod, struct stream *s) s->p = phold + len; } } + else if (type == 100) // metadata commands. + { + LOG_DEVEL(LOG_LEVEL_INFO, + "lib_mod_process_message: type 100 len %d", len); + for (index = 0; index < num_orders; ++index) + { + phold = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); + switch (type) + { + case 3: // memory allocation complete + in_uint16_le(s, width); + in_uint16_le(s, height); + LOG(LOG_LEVEL_INFO, "Received memory_allocation_complete" + " command. width: %d, height: %d", + width, height); + rv = mod->server_reset(mod, width, height, 0); + break; + } + s->p = phold + len; + } + } else { LOG_DEVEL(LOG_LEVEL_TRACE, "unknown type %d", type); From c96156340311fce5b40ed6a06826ee2256d98092 Mon Sep 17 00:00:00 2001 From: jsorg71 Date: Sun, 14 Jan 2024 21:17:59 -0800 Subject: [PATCH 08/21] =?UTF-8?q?GFX:=20sort=20versions,=20flags=20to=20re?= =?UTF-8?q?turn=20the=20highest=20version=20we=20support=20in=E2=80=A6=20(?= =?UTF-8?q?#2911)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * GFX: sort versions, flags to return the highest version we support in caps advertise * GFX: simpify swtich in caps_advertise * GFX: log skipped capability versions in caps_advertise --- common/os_calls.c | 8 ++++++ common/os_calls.h | 3 ++ xrdp/xrdp_mm.c | 70 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/common/os_calls.c b/common/os_calls.c index 60d7705f..b8f6b633 100644 --- a/common/os_calls.c +++ b/common/os_calls.c @@ -4199,3 +4199,11 @@ g_no_new_privs(void) return 0; #endif } + +/*****************************************************************************/ +void +g_qsort(void *base, size_t nitems, size_t size, + int (*compar)(const void *, const void *)) +{ + qsort(base, nitems, size, compar); +} diff --git a/common/os_calls.h b/common/os_calls.h index 02758e89..aa64b41f 100644 --- a/common/os_calls.h +++ b/common/os_calls.h @@ -400,6 +400,9 @@ int g_tcp4_bind_address(int sck, const char *port, const char *address); int g_tcp6_socket(void); int g_tcp6_bind_address(int sck, const char *port, const char *address); int g_no_new_privs(void); +void +g_qsort(void *base, size_t nitems, size_t size, + int (*compar)(const void *, const void *)); /* glib-style wrappers */ #define g_new(struct_type, n_structs) \ diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 42faea61..7802df41 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -1174,6 +1174,20 @@ advance_resize_state_machine(struct xrdp_mm *mm, return 0; } +struct ver_flags_t +{ + int version; + int flags; +}; + +/******************************************************************************/ +static int +cmpverfunc (const void *a, const void *b) +{ + return ((struct ver_flags_t *)a)->version - + ((struct ver_flags_t *)b)->version; +} + /******************************************************************************/ static int xrdp_mm_egfx_caps_advertise(void *user, int caps_count, @@ -1188,6 +1202,7 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count, int error; int version; int flags; + struct ver_flags_t *ver_flags; LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise:"); self = (struct xrdp_mm *) user; @@ -1196,18 +1211,32 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count, { LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: can not do gfx"); } + /* create copy for sorting */ + ver_flags = g_new(struct ver_flags_t, caps_count); + if (ver_flags == NULL) + { + return 1; + } + for (index = 0; index < caps_count; index++) + { + ver_flags[index].version = versions[index]; + ver_flags[index].flags = flagss[index]; + } + /* sort by version */ + g_qsort(ver_flags, caps_count, sizeof(struct ver_flags_t), cmpverfunc); best_index = -1; best_h264_index = -1; best_pro_index = -1; for (index = 0; index < caps_count; index++) { - version = versions[index]; - flags = flagss[index]; + version = ver_flags[index].version; + flags = ver_flags[index].flags; LOG(LOG_LEVEL_INFO, " version 0x%8.8x flags 0x%8.8x (index: %d)", version, flags, index); switch (version) { - case XR_RDPGFX_CAPVERSION_8: + case XR_RDPGFX_CAPVERSION_8: /* FALLTHROUGH */ + case XR_RDPGFX_CAPVERSION_101: best_pro_index = index; break; case XR_RDPGFX_CAPVERSION_81: @@ -1218,29 +1247,27 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count, best_pro_index = index; break; case XR_RDPGFX_CAPVERSION_10: - best_pro_index = index; - break; - case XR_RDPGFX_CAPVERSION_101: - best_pro_index = index; - break; - case XR_RDPGFX_CAPVERSION_102: - best_pro_index = index; - break; - case XR_RDPGFX_CAPVERSION_103: - best_pro_index = index; - break; - case XR_RDPGFX_CAPVERSION_104: if (!(flags & XR_RDPGFX_CAPS_FLAG_AVC_DISABLED)) { best_h264_index = index; } best_pro_index = index; break; - case XR_RDPGFX_CAPVERSION_105: + case XR_RDPGFX_CAPVERSION_102: /* FALLTHROUGH */ + case XR_RDPGFX_CAPVERSION_103: /* FALLTHROUGH */ + case XR_RDPGFX_CAPVERSION_104: /* FALLTHROUGH */ + case XR_RDPGFX_CAPVERSION_105: /* FALLTHROUGH */ + case XR_RDPGFX_CAPVERSION_106: /* FALLTHROUGH */ + case XR_RDPGFX_CAPVERSION_107: + if (!(flags & XR_RDPGFX_CAPS_FLAG_AVC_DISABLED)) + { + best_h264_index = index; + } best_pro_index = index; break; - case XR_RDPGFX_CAPVERSION_106: - best_pro_index = index; + default: + /* just skip unknwown */ + LOG(LOG_LEVEL_INFO, "unknown version 0x%8.8x", version); break; } } @@ -1260,10 +1287,10 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count, if (best_index >= 0) { LOG(LOG_LEVEL_INFO, " replying version 0x%8.8x flags 0x%8.8x", - versions[best_index], flagss[best_index]); + ver_flags[best_index].version, ver_flags[best_index].flags); error = xrdp_egfx_send_capsconfirm(self->egfx, - versions[best_index], - flagss[best_index]); + ver_flags[best_index].version, + ver_flags[best_index].flags); LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_caps_advertise: xrdp_egfx_send_capsconfirm " "error %d best_index %d", error, best_index); error = xrdp_egfx_send_reset_graphics(self->egfx, @@ -1307,6 +1334,7 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count, self->encoder = xrdp_encoder_create(self); xrdp_bitmap_invalidate(screen, &lrect); } + g_free(ver_flags); return 0; } From c08cebb01d9bcaed22d68114450078eeebe9e0d6 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Wed, 17 Jan 2024 00:23:27 -0500 Subject: [PATCH 09/21] Making SHM read only from xup --- xup/xup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xup/xup.c b/xup/xup.c index b40b1e9e..8720b005 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -1275,7 +1275,7 @@ process_server_set_pointer_shmfd(struct mod *amod, struct stream *s) { Bpp = (bpp == 0) ? 3 : (bpp + 7) / 8; shmembytes = width * height * Bpp + width * height / 8; - if (g_file_map(fd, 1, 1, shmembytes, &shmemptr) == 0) + if (g_file_map(fd, 1, 0, shmembytes, &shmemptr) == 0) { cur_data = (char *)shmemptr; cur_mask = cur_data + width * height * Bpp; @@ -1368,7 +1368,7 @@ process_server_paint_rect_shmfd(struct mod *amod, struct stream *s) { if (num_fds == 1) { - if (g_file_map(fd, 1, 1, shmem_bytes, &shmem_ptr) == 0) + if (g_file_map(fd, 1, 0, shmem_bytes, &shmem_ptr) == 0) { bmpdata = (char *)shmem_ptr; bmpdata += shmem_offset; From 2e1f7f1484ad795c39315faf27d3a540ddd13158 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Thu, 18 Jan 2024 00:40:19 -0500 Subject: [PATCH 10/21] Adding KEY_FRAME_REQUESTED parameter. --- common/xrdp_client_info.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index ad5012bb..3acb13bf 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -223,7 +223,8 @@ enum xrdp_encoder_flags NONE = 0, ENCODE_COMPLETE = 1 << 0, GFX_PROGRESSIVE_RFX = 1 << 1, - GFX_H264 = 1 << 2 + GFX_H264 = 1 << 2, + KEY_FRAME_REQUESTED = 1 << 3 }; /* yyyymmdd of last incompatible change to xrdp_client_info */ From 97b2527018ed79272f767dacb3c2fdd71701cdf1 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Mon, 22 Jan 2024 12:02:45 -0500 Subject: [PATCH 11/21] Enabling RFX_PRO key frame handling. - Also update librfxcodec --- .gitmodules | 1 - xrdp/xrdp_encoder.c | 27 +++++++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.gitmodules b/.gitmodules index 66ec2efd..8758a098 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,6 @@ url = https://github.com/neutrinolabs/librfxcodec.git branch = . ignore = untracked - [submodule "libpainter"] path = libpainter url = https://github.com/neutrinolabs/libpainter.git diff --git a/xrdp/xrdp_encoder.c b/xrdp/xrdp_encoder.c index c2892b76..3eb75699 100644 --- a/xrdp/xrdp_encoder.c +++ b/xrdp/xrdp_encoder.c @@ -363,6 +363,8 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) struct rfx_tile *tiles; struct rfx_rect *rfxrects; int alloc_bytes; + int encode_flags; + int encode_passes; LOG_DEVEL(LOG_LEVEL_DEBUG, "process_enc_rfx:"); LOG_DEVEL(LOG_LEVEL_DEBUG, "process_enc_rfx: num_crects %d num_drects %d", @@ -372,6 +374,7 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) event_processed = self->xrdp_encoder_event_processed; all_tiles_written = 0; + encode_passes = 0; do { tiles_written = 0; @@ -423,15 +426,23 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) } out_data_bytes = self->max_compressed_bytes; - tiles_written = rfxcodec_encode(self->codec_handle, - out_data + XRDP_SURCMD_PREFIX_BYTES, - &out_data_bytes, enc->data, - enc->width, enc->height, - enc->width * 4, - rfxrects, enc->num_drects, - tiles, enc->num_crects, - self->quants, self->num_quants); + + encode_flags = 0; + if (((int)enc->flags & KEY_FRAME_REQUESTED) && encode_passes == 0) + { + encode_flags = RFX_FLAGS_PRO_KEY; + } + tiles_written = rfxcodec_encode_ex(self->codec_handle, + out_data + XRDP_SURCMD_PREFIX_BYTES, + &out_data_bytes, enc->data, + enc->width, enc->height, + enc->width * 4, + rfxrects, enc->num_drects, + tiles, enc->num_crects, + self->quants, self->num_quants, + encode_flags); } + ++encode_passes; } LOG_DEVEL(LOG_LEVEL_DEBUG, From 3fab31c64415d8fb0a75ad496ec81f99be1b036a Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Tue, 23 Jan 2024 11:18:28 -0800 Subject: [PATCH 12/21] GFX: fix multimon login screen drawing --- xrdp/xrdp.h | 3 +- xrdp/xrdp_mm.c | 156 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 141 insertions(+), 18 deletions(-) diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index ba281fa0..00843fa9 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -500,7 +500,8 @@ xrdp_mm_frame_ack(struct xrdp_mm *self, int frame_id); int xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, struct xrdp_bitmap *bitmap, - struct xrdp_rect *rect); + struct xrdp_rect *rect, + int surface_id, int x, int y); int server_begin_update(struct xrdp_mod *mod); int diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 7802df41..555d153c 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -951,7 +951,8 @@ xrdp_mm_process_rail_drawing_orders(struct xrdp_mm *self, struct stream *s) int xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, struct xrdp_bitmap *bitmap, - struct xrdp_rect *rect) + struct xrdp_rect *rect, int surface_id, + int x, int y) { struct xrdp_egfx_rect gfx_rect; struct stream *comp_s; @@ -970,6 +971,10 @@ xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, int cy; LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap:"); + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: " + "surface_id %d rect %d %d %d %d x %d y %d", + surface_id, rect->left, rect->top, rect->right, rect->bottom, + x, y); bwidth = rect->right - rect->left; bheight = rect->bottom - rect->top; if ((bwidth < 1) || (bheight < 1)) @@ -1052,11 +1057,11 @@ xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, comp_bytes = (int)(comp_s->end - comp_s->data); LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap: lines %d " "comp_bytes %d", lines, comp_bytes); - gfx_rect.x1 = xindex; - gfx_rect.y1 = yindex; - gfx_rect.x2 = xindex + bwidth; - gfx_rect.y2 = yindex + bheight; - if (xrdp_egfx_send_wire_to_surface1(self->egfx, self->egfx->surface_id, + gfx_rect.x1 = xindex - x; + gfx_rect.y1 = yindex - y; + gfx_rect.x2 = gfx_rect.x1 + bwidth; + gfx_rect.y2 = gfx_rect.y1 + bheight; + if (xrdp_egfx_send_wire_to_surface1(self->egfx, surface_id, XR_RDPGFX_CODECID_PLANAR, XR_PIXEL_FORMAT_XRGB_8888, &gfx_rect, comp_s->data, @@ -1188,6 +1193,59 @@ cmpverfunc (const void *a, const void *b) ((struct ver_flags_t *)b)->version; } +/******************************************************************************/ +static int +xrdp_mm_egfx_create_surfaces(struct xrdp_mm *self) +{ + int surface_id; + int index; + int count; + int left; + int top; + int width; + int height; + struct monitor_info *mi; + struct xrdp_bitmap *screen; + + screen = self->wm->screen; + count = self->wm->client_info->display_sizes.monitorCount; + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_egfx_create_surfaces: " + "monitor count %d", count); + if (count < 1) + { + left = 0; + top = 0; + width = screen->width; + height = screen->height; + xrdp_egfx_send_create_surface(self->egfx, self->egfx->surface_id, + width, height, + XR_PIXEL_FORMAT_XRGB_8888); + xrdp_egfx_send_map_surface(self->egfx, self->egfx->surface_id, + left, top); + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_create_surfaces: map " + "surface_id %d left %d top %d width %d height %d", + self->egfx->surface_id, left, top, width, height); + return 0; + } + for (index = 0; index < count; index++) + { + surface_id = index; + mi = self->wm->client_info->display_sizes.minfo_wm + index; + left = mi->left; + top = mi->top; + width = mi->right - mi->left + 1; + height = mi->bottom - mi->top + 1; + xrdp_egfx_send_create_surface(self->egfx, surface_id, + width, height, + XR_PIXEL_FORMAT_XRGB_8888); + xrdp_egfx_send_map_surface(self->egfx, surface_id, left, top); + LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_create_surfaces: map " + "surface_id %d left %d top %d width %d height %d", + surface_id, left, top, width, height); + } + return 0; +} + /******************************************************************************/ static int xrdp_mm_egfx_caps_advertise(void *user, int caps_count, @@ -1301,10 +1359,7 @@ xrdp_mm_egfx_caps_advertise(void *user, int caps_count, "error %d monitorCount %d", error, self->wm->client_info->display_sizes.monitorCount); self->egfx_up = 1; - xrdp_egfx_send_create_surface(self->egfx, self->egfx->surface_id, - screen->width, screen->height, - XR_PIXEL_FORMAT_XRGB_8888); - xrdp_egfx_send_map_surface(self->egfx, self->egfx->surface_id, 0, 0); + xrdp_mm_egfx_create_surfaces(self); self->encoder = xrdp_encoder_create(self); xrdp_mm_egfx_invalidate_all(self); @@ -3448,6 +3503,79 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) return 0; } +/*****************************************************************************/ +static int +xrdp_mm_draw_dirty(struct xrdp_mm *self) +{ + struct xrdp_rect rect; + struct xrdp_rect mon_rect; + struct xrdp_region *mon_reg; + int error; + int index; + int jndex; + int count; + int surface_id; + struct monitor_info *mi; + + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_draw_dirty:"); + count = self->wm->client_info->display_sizes.monitorCount; + if (count < 1) + { + error = xrdp_region_get_bounds(self->wm->screen_dirty_region, &rect); + if (error == 0) + { + xrdp_mm_egfx_send_planar_bitmap(self, + self->wm->screen, &rect, + self->egfx->surface_id, 0, 0); + } + } + else + { + for (index = 0; index < count; index++) + { + /* make a copy of screen_dirty_region */ + mon_reg = xrdp_region_create(self->wm); + if (mon_reg == NULL) + { + return 1; + } + jndex = 0; + while (xrdp_region_get_rect(self->wm->screen_dirty_region, + jndex, &mon_rect) == 0) + { + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_draw_dirty: jndex %d " + "mon_rect %d %d %d %d", + jndex, mon_rect.left, mon_rect.top, + mon_rect.right, mon_rect.bottom); + xrdp_region_add_rect(mon_reg, &mon_rect); + jndex++; + } + /* intercect monitor */ + mi = self->wm->client_info->display_sizes.minfo_wm + index; + mon_rect.left = mi->left; + mon_rect.top = mi->top; + mon_rect.right = mi->right + 1; + mon_rect.bottom = mi->bottom + 1; + xrdp_region_intersect_rect(mon_reg, &mon_rect); + if (xrdp_region_not_empty(mon_reg)) + { + error = xrdp_region_get_bounds(mon_reg, &rect); + if (error == 0) + { + surface_id = index; + xrdp_mm_egfx_send_planar_bitmap(self, + self->wm->screen, + &rect, + surface_id, + mi->left, mi->top); + } + } + xrdp_region_delete(mon_reg); + } + } + return 0; +} + /*****************************************************************************/ int xrdp_mm_check_wait_objs(struct xrdp_mm *self) @@ -3528,8 +3656,6 @@ xrdp_mm_check_wait_objs(struct xrdp_mm *self) { if (xrdp_region_not_empty(self->wm->screen_dirty_region)) { - int error; - struct xrdp_rect rect; int now = g_time3(); int diff = now - self->wm->last_screen_draw_time; LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_check_wait_objs: not empty diff %d", diff); @@ -3537,11 +3663,7 @@ xrdp_mm_check_wait_objs(struct xrdp_mm *self) { if (self->egfx_up) { - error = xrdp_region_get_bounds(self->wm->screen_dirty_region, &rect); - if (error == 0) - { - xrdp_mm_egfx_send_planar_bitmap(self, self->wm->screen, &rect); - } + xrdp_mm_draw_dirty(self); xrdp_region_delete(self->wm->screen_dirty_region); self->wm->screen_dirty_region = NULL; self->wm->last_screen_draw_time = now; From ccead296e615b92afc17daf67447876fb3c122e0 Mon Sep 17 00:00:00 2001 From: Christopher Pitstick Date: Thu, 25 Jan 2024 14:21:55 -0500 Subject: [PATCH 13/21] Fix service call filter. --- instfiles/xrdp.service.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/instfiles/xrdp.service.in b/instfiles/xrdp.service.in index 814d4de5..be24535a 100644 --- a/instfiles/xrdp.service.in +++ b/instfiles/xrdp.service.in @@ -10,7 +10,9 @@ EnvironmentFile=-@sysconfdir@/sysconfig/xrdp EnvironmentFile=-@sysconfdir@/default/xrdp ExecStart=@sbindir@/xrdp $XRDP_OPTIONS --nodaemon SystemCallArchitectures=native -SystemCallFilter=@basic-io @file-system @io-event @ipc @network-io @process @signal ioctl madvise sysinfo uname +SystemCallFilter=@basic-io @file-system @io-event @ipc @network-io @process +SystemCallFilter=@signal @system-service ioctl madvise sysinfo uname +SystemCallErrorNumber=EPERM [Install] WantedBy=multi-user.target From e5d455d0be7b55e765e885abab4d88367171dfec Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 24 Jan 2024 09:35:22 +0000 Subject: [PATCH 14/21] error-check xrdp_mm_egfx_send_planar_bitmap() paths Without some checking for this call, it's possible for the xrdp process to never end when the client goes away. --- xrdp/xrdp_mm.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 555d153c..62082022 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -969,9 +969,10 @@ xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, int bheight; int cx; int cy; + int rv = 0; LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap:"); - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: " + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_egfx_send_planar_bitmap: " "surface_id %d rect %d %d %d %d x %d y %d", surface_id, rect->left, rect->top, rect->right, rect->bottom, x, y); @@ -1019,6 +1020,8 @@ xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, { LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: " "xrdp_egfx_send_frame_start error"); + rv = 1; + goto cleanup; } LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_egfx_send_planar_bitmap: left %d top %d right %d " @@ -1069,6 +1072,8 @@ xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, { LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: " "xrdp_egfx_send_wire_to_surface1 error"); + rv = 1; + goto cleanup; } } } @@ -1077,11 +1082,13 @@ xrdp_mm_egfx_send_planar_bitmap(struct xrdp_mm *self, { LOG(LOG_LEVEL_INFO, "xrdp_mm_egfx_send_planar_bitmap: " "xrdp_egfx_send_frame_end error"); + rv = 1; } +cleanup: g_free(pixels); free_stream(comp_s); free_stream(temp_s); - return 0; + return rv; } /******************************************************************************/ @@ -3516,17 +3523,18 @@ xrdp_mm_draw_dirty(struct xrdp_mm *self) int count; int surface_id; struct monitor_info *mi; + int rv = 0; - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_mm_draw_dirty:"); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_draw_dirty:"); count = self->wm->client_info->display_sizes.monitorCount; if (count < 1) { error = xrdp_region_get_bounds(self->wm->screen_dirty_region, &rect); if (error == 0) { - xrdp_mm_egfx_send_planar_bitmap(self, - self->wm->screen, &rect, - self->egfx->surface_id, 0, 0); + rv = xrdp_mm_egfx_send_planar_bitmap(self, + self->wm->screen, &rect, + self->egfx->surface_id, 0, 0); } } else @@ -3563,17 +3571,17 @@ xrdp_mm_draw_dirty(struct xrdp_mm *self) if (error == 0) { surface_id = index; - xrdp_mm_egfx_send_planar_bitmap(self, - self->wm->screen, - &rect, - surface_id, - mi->left, mi->top); + rv = xrdp_mm_egfx_send_planar_bitmap(self, + self->wm->screen, + &rect, + surface_id, + mi->left, mi->top); } } xrdp_region_delete(mon_reg); } } - return 0; + return rv; } /*****************************************************************************/ @@ -3663,7 +3671,7 @@ xrdp_mm_check_wait_objs(struct xrdp_mm *self) { if (self->egfx_up) { - xrdp_mm_draw_dirty(self); + rv = xrdp_mm_draw_dirty(self); xrdp_region_delete(self->wm->screen_dirty_region); self->wm->screen_dirty_region = NULL; self->wm->last_screen_draw_time = now; From d23d147dc775dbee9c8fe678d4549e9937cbce06 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Tue, 23 Jan 2024 16:55:48 +0000 Subject: [PATCH 15/21] Don't enable GFX if client doesn't support 32 BPP mstsc.exe indicates it supports GFX in the early capability flags, even if it not able to support 32 BPP. This results in a session failure if a RDPGFX_CAPS_CONFIRM_PDU is sent on the EGFX virtual channel. --- libxrdp/xrdp_sec.c | 14 ++++++++++++-- xrdp/xrdp_mm.c | 3 +-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 6c2057ae..bc3551fd 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -2138,15 +2138,25 @@ xrdp_sec_process_mcs_data_CS_CORE(struct xrdp_sec *self, struct stream *s) { client_info->bpp = 32; } +#ifdef XRDP_RFXCODEC if (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) { - LOG(LOG_LEVEL_INFO, "client supports gfx protocol"); - self->rdp_layer->client_info.gfx = 1; + if (client_info->bpp < 32) + { + LOG(LOG_LEVEL_WARNING, + "client requested gfx protocol with insufficient color depth"); + } + else + { + LOG(LOG_LEVEL_INFO, "client supports gfx protocol"); + self->rdp_layer->client_info.gfx = 1; + } } else { LOG_DEVEL(LOG_LEVEL_INFO, "client DOES NOT support gfx"); } +#endif if (!s_check_rem(s, 64)) { return 0; diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 62082022..6d6279f1 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -1484,8 +1484,7 @@ int egfx_initialize(struct xrdp_mm *self) { LOG_DEVEL(LOG_LEVEL_TRACE, "egfx_initialize"); - if (!(self->wm->client_info->mcs_early_capability_flags - & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL)) + if (!(self->wm->client_info->gfx)) { return 0; } From d9783a952938ea1d0823458bee2297e8c76fa6d7 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 25 Jan 2024 15:22:45 +0000 Subject: [PATCH 16/21] Don't pass drdynvc to neutrinoRDP Since v0.9.9, xrdp has assumed that the "drdynvc" static virtual channel is available for its exclusive use. With GFX support, it is necessary to codify this to prevent this sequence of operations:- - NeutrinoRDP target sends DVC Capabilities Request PDU - target responds wih DVC Capabilities Response PDU - xrdp processes this, starting the GFX virtual channel again In the future, if NeutrinoRDP requires access to virtual channels, data may somehow need to be passed through to the target while being parsed and handled appropriately within xrdp. --- common/ms-rdpbcgr.h | 6 +++++- libxrdp/xrdp_sec.c | 4 ++-- neutrinordp/xrdp-neutrinordp.c | 37 +++++++++++++++++++++++----------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/common/ms-rdpbcgr.h b/common/ms-rdpbcgr.h index 6e390535..11d50bdd 100644 --- a/common/ms-rdpbcgr.h +++ b/common/ms-rdpbcgr.h @@ -85,11 +85,15 @@ #define CONNECTION_TYPE_LAN 0x06 #define CONNECTION_TYPE_AUTODETECT 0x07 -/* Channel definition structure CHANNEL_DEF (2.2.1.3.4.1) */ +/* TS_UD_CS_NET (2.2.1.3.4) */ /* This isn't explicitly named in MS-RDPBCGR */ +#define MAX_STATIC_CHANNELS 31 + +/* Channel definition structure CHANNEL_DEF (2.2.1.3.4.1) */ #define CHANNEL_NAME_LEN 7 /* These names are also not explicitly defined in MS-RDPBCGR */ #define CLIPRDR_SVC_CHANNEL_NAME "cliprdr" +#define DRDYNVC_SVC_CHANNEL_NAME "drdynvc" #define RAIL_SVC_CHANNEL_NAME "rail" #define RDPSND_SVC_CHANNEL_NAME "rdpsnd" #define RDPDR_SVC_CHANNEL_NAME "rdpdr" diff --git a/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index bc3551fd..f2d1a4d4 100644 --- a/libxrdp/xrdp_sec.c +++ b/libxrdp/xrdp_sec.c @@ -2388,10 +2388,10 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s) in_uint32_le(s, num_channels); LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_UD_CS_NET " "channelCount %d", num_channels); - if (num_channels > 31) + if (num_channels > MAX_STATIC_CHANNELS) { LOG(LOG_LEVEL_ERROR, "[MS-RDPBCGR] Protocol error: too many channels requested. " - "max 31, received %d", num_channels); + "max %d, received %d", MAX_STATIC_CHANNELS, num_channels); return 1; } diff --git a/neutrinordp/xrdp-neutrinordp.c b/neutrinordp/xrdp-neutrinordp.c index 5e6c1216..70ddc96d 100644 --- a/neutrinordp/xrdp-neutrinordp.c +++ b/neutrinordp/xrdp-neutrinordp.c @@ -1790,8 +1790,10 @@ lfreerdp_pre_connect(freerdp *instance) int index; int error; int num_chans; + int target_chan; int ch_flags; char ch_name[256]; + const char *ch_names[MAX_STATIC_CHANNELS]; char *dst_ch_name; LOG_DEVEL(LOG_LEVEL_INFO, "lfreerdp_pre_connect:"); @@ -1805,6 +1807,7 @@ lfreerdp_pre_connect(freerdp *instance) num_chans = 0; } + target_chan = 0; for (index = 0 ; index < num_chans; ++index) { error = mod->server_query_channel(mod, index, ch_name, &ch_flags); @@ -1813,21 +1816,31 @@ lfreerdp_pre_connect(freerdp *instance) LOG_DEVEL(LOG_LEVEL_DEBUG, "lfreerdp_pre_connect: " "got channel [%s], id [%d], flags [0x%8.8x]", ch_name, index, ch_flags); - dst_ch_name = instance->settings->channels[index].name; - g_memset(dst_ch_name, 0, 8); - g_snprintf(dst_ch_name, 8, "%s", ch_name); - instance->settings->channels[index].options = ch_flags; - } - else - { - LOG(LOG_LEVEL_ERROR, "lfreerdp_pre_connect: " - "Expected %d channels, got %d", - num_chans, index); - num_chans = index; + + if (g_strcmp(ch_name, DRDYNVC_SVC_CHANNEL_NAME) == 0) + { + /* xrdp currently reserves dynamic channels for its + * exclusive use (e.g. for GFX support) */ + LOG(LOG_LEVEL_INFO, "Channel '%s' not passed to module", + ch_name); + } + else if (target_chan < MAX_STATIC_CHANNELS) + { + dst_ch_name = instance->settings->channels[target_chan].name; + ch_names[target_chan] = dst_ch_name; + g_memset(dst_ch_name, 0, CHANNEL_NAME_LEN + 1); + g_snprintf(dst_ch_name, CHANNEL_NAME_LEN + 1, "%s", ch_name); + instance->settings->channels[target_chan].options = ch_flags; + ++target_chan; + } } } - instance->settings->num_channels = num_chans; + g_strnjoin(ch_name, sizeof(ch_name), ",", ch_names, target_chan); + LOG(LOG_LEVEL_INFO, "Static channels (from %d) passed to module : %s", + num_chans, ch_name); + + instance->settings->num_channels = target_chan; instance->settings->offscreen_bitmap_cache = 0; instance->settings->draw_nine_grid = 0; From 54acca43cfe85d60f8a8963fe7ac84cd293d5be2 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 31 Jan 2024 22:14:56 +0000 Subject: [PATCH 17/21] Resize state machine: A fix and a question (#2929) * Store EGFX state before entering resize state machine At present the EGFX state is destroyed by states WMRZ_EGFX_DELETE_SURFACE through WRMZ_EGFX_DELETE. This means that at WMRZ_EGFX_INITIALIZE we cannot distinguish between EGFX not being ever used, and EGFX having been torn down. Consequently, when running non-GFX, we don't correctly recover the session. * Allow multiple reasons for suppress_output Replaces the single boolean for suppress_output with a bitmask, to allow output to be suppressed for more than one reason * Disable output during resize * Add states to dynamic resize Adds states to the dynamic resize state machine so we wait for a Deactivation-Reactivation sequence to finish before sending pointer updates, etc. * suppress module output during the dynamic resize * Add support for dynamic resize to VNC backend xrdp_mm needs to be informed when a resize has been performed so that the resize stte machine can be updsate. --- common/xrdp_client_info.h | 10 ++- libxrdp/libxrdp.c | 6 ++ libxrdp/libxrdp.h | 29 +++++++++ libxrdp/xrdp_rdp.c | 128 +++++++++++++++++++++++--------------- vnc/vnc.c | 6 ++ xrdp/xrdp.h | 5 ++ xrdp/xrdp_mm.c | 57 +++++++++++++---- xrdp/xrdp_types.h | 10 ++- xrdp/xrdp_wm.c | 3 + 9 files changed, 189 insertions(+), 65 deletions(-) diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h index 3acb13bf..03dd5e3c 100644 --- a/common/xrdp_client_info.h +++ b/common/xrdp_client_info.h @@ -199,7 +199,9 @@ struct xrdp_client_info int no_orders_supported; int use_cache_glyph_v2; int rail_enable; - int suppress_output; + // Mask of reasons why output may be suppressed + // (see enum suppress_output_reason) + unsigned int suppress_output_mask; int enable_token_login; char domain_user_separator[16]; @@ -227,6 +229,12 @@ enum xrdp_encoder_flags KEY_FRAME_REQUESTED = 1 << 3 }; +/* + * Return true if output is suppressed for a particular reason + */ +#define OUTPUT_SUPPRESSED_FOR_REASON(ci,reason) \ + (((ci)->suppress_output_mask & (unsigned int)reason) != 0) + /* yyyymmdd of last incompatible change to xrdp_client_info */ /* also used for changes to all the xrdp installed headers */ #define CLIENT_INFO_CURRENT_VERSION 20230425 diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c index 358a4418..af1714de 100644 --- a/libxrdp/libxrdp.c +++ b/libxrdp/libxrdp.c @@ -1181,6 +1181,12 @@ libxrdp_reset(struct xrdp_session *session, return 1; } + /* + * Stop output from the client during the deactivation-reactivation + * sequence [MS-RDPBCGR] 1.3.1.3 */ + xrdp_rdp_suppress_output((struct xrdp_rdp *)session->rdp, 1, + XSO_REASON_DEACTIVATE_REACTIVATE, 0, 0, 0, 0); + /* shut down the rdp client * * When resetting the lib, disable application input checks, as diff --git a/libxrdp/libxrdp.h b/libxrdp/libxrdp.h index 4b7c906c..b9d1b8f9 100644 --- a/libxrdp/libxrdp.h +++ b/libxrdp/libxrdp.h @@ -403,6 +403,20 @@ int xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s); /* xrdp_rdp.c */ + +/** + * Reasons why output is being suppressed or restarted + */ +enum suppress_output_reason +{ + /// Client has requested suppress via TS_SUPPRESS_OUTPUT_PDU + XSO_REASON_CLIENT_REQUEST = (1 << 0), + /// Deactivation-Reactivation Sequence [MS-RDPBCGR] 1.3.1.3 + XSO_REASON_DEACTIVATE_REACTIVATE = (1 << 1), + /// Dynamic resize in progress + XSO_REASON_DYNAMIC_RESIZE = (1 << 2) +}; + struct xrdp_rdp * xrdp_rdp_create(struct xrdp_session *session, struct trans *trans); void @@ -438,6 +452,21 @@ xrdp_rdp_send_deactivate(struct xrdp_rdp *self); int xrdp_rdp_send_session_info(struct xrdp_rdp *self, const char *data, int data_bytes); +/** + * Request output suppress or resume + * + * @param self RDP struct + * @param suppress (!= 0 for suppress, 0 for resume) + * @param reason Why the output is being suppressed or resumed + * @param left Left pixel of repaint area (ignored for suppress) + * @param top Top pixel of repaint area (ignored for suppress) + * @param right Right pixel of inclusive repaint area (ignored for suppress) + * @param bottom Bottom pixel of inclusive repaint area (ignored for suppress) + */ +void +xrdp_rdp_suppress_output(struct xrdp_rdp *self, int suppress, + enum suppress_output_reason reason, + int left, int top, int right, int bottom); /* xrdp_orders.c */ struct xrdp_orders * diff --git a/libxrdp/xrdp_rdp.c b/libxrdp/xrdp_rdp.c index f9196d4b..29901db6 100644 --- a/libxrdp/xrdp_rdp.c +++ b/libxrdp/xrdp_rdp.c @@ -1292,6 +1292,20 @@ xrdp_rdp_process_data_font(struct xrdp_rdp *self, struct stream *s) self->session->up_and_running = 1; LOG_DEVEL(LOG_LEVEL_INFO, "yeah, up_and_running"); xrdp_rdp_send_data_update_sync(self); + + /* This is also the end of an Deactivation-reactivation + * sequence [MS-RDPBCGR] 1.3.1.3 */ + xrdp_rdp_suppress_output(self, 0, XSO_REASON_DEACTIVATE_REACTIVATE, + 0, 0, + self->client_info.display_sizes.session_width, + self->client_info.display_sizes.session_height); + + if (self->session->callback != 0) + { + /* call to xrdp_wm.c : callback */ + self->session->callback(self->session->id, 0x555a, 0, 0, + 0, 0); + } xrdp_channel_drdynvc_start(self->sec_layer->chan_layer); } else @@ -1401,69 +1415,83 @@ xrdp_rdp_process_frame_ack(struct xrdp_rdp *self, struct stream *s) return 0; } +/*****************************************************************************/ +void +xrdp_rdp_suppress_output(struct xrdp_rdp *self, int suppress, + enum suppress_output_reason reason, + int left, int top, int right, int bottom) +{ + int old_suppress = self->client_info.suppress_output_mask != 0; + if (suppress) + { + self->client_info.suppress_output_mask |= (unsigned int)reason; + } + else + { + self->client_info.suppress_output_mask &= ~(unsigned int)reason; + } + + int current_suppress = self->client_info.suppress_output_mask != 0; + if (current_suppress != old_suppress && self->session->callback != 0) + { + self->session->callback(self->session->id, 0x5559, suppress, + MAKELONG(left, top), + MAKELONG(right, bottom), 0); + } +} + /*****************************************************************************/ /* Process a [MS-RDPBCGR] TS_SUPPRESS_OUTPUT_PDU message */ static int xrdp_rdp_process_suppress(struct xrdp_rdp *self, struct stream *s) { + int rv = 1; int allowDisplayUpdates; int left; int top; int right; int bottom; - if (!s_check_rem_and_log(s, 1, "Parsing [MS-RDPBCGR] TS_SUPPRESS_OUTPUT_PDU")) + if (s_check_rem_and_log(s, 1, "Parsing [MS-RDPBCGR] TS_SUPPRESS_OUTPUT_PDU")) { - return 1; + in_uint8(s, allowDisplayUpdates); + LOG_DEVEL(LOG_LEVEL_TRACE, + "Received [MS-RDPBCGR] TS_SUPPRESS_OUTPUT_PDU " + "allowDisplayUpdates %d", allowDisplayUpdates); + switch (allowDisplayUpdates) + { + case 0: /* SUPPRESS_DISPLAY_UPDATES */ + LOG_DEVEL(LOG_LEVEL_DEBUG, + "Client requested display output to be suppressed"); + xrdp_rdp_suppress_output(self, 1, + XSO_REASON_CLIENT_REQUEST, + 0, 0, 0, 0); + rv = 0; + break; + case 1: /* ALLOW_DISPLAY_UPDATES */ + LOG_DEVEL(LOG_LEVEL_DEBUG, + "Client requested display output to be enabled"); + if (s_check_rem_and_log(s, 11, + "Parsing [MS-RDPBCGR] Padding and TS_RECTANGLE16")) + { + in_uint8s(s, 3); /* pad */ + in_uint16_le(s, left); + in_uint16_le(s, top); + in_uint16_le(s, right); + in_uint16_le(s, bottom); + LOG_DEVEL(LOG_LEVEL_TRACE, + "Received [MS-RDPBCGR] TS_RECTANGLE16 " + "left %d, top %d, right %d, bottom %d", + left, top, right, bottom); + xrdp_rdp_suppress_output(self, 0, + XSO_REASON_CLIENT_REQUEST, + left, top, right, bottom); + rv = 0; + } + break; + } } - in_uint8(s, allowDisplayUpdates); - LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_SUPPRESS_OUTPUT_PDU " - "allowDisplayUpdates %d", allowDisplayUpdates); - switch (allowDisplayUpdates) - { - case 0: /* SUPPRESS_DISPLAY_UPDATES */ - self->client_info.suppress_output = 1; - LOG_DEVEL(LOG_LEVEL_DEBUG, "Client requested display output to be suppressed"); - if (self->session->callback != 0) - { - self->session->callback(self->session->id, 0x5559, 1, - 0, 0, 0); - } - else - { - LOG_DEVEL(LOG_LEVEL_WARNING, - "Bug: no callback registered for xrdp_rdp_process_suppress"); - } - break; - case 1: /* ALLOW_DISPLAY_UPDATES */ - self->client_info.suppress_output = 0; - LOG_DEVEL(LOG_LEVEL_DEBUG, "Client requested display output to be enabled"); - if (!s_check_rem_and_log(s, 11, "Parsing [MS-RDPBCGR] Padding and TS_RECTANGLE16")) - { - return 1; - } - in_uint8s(s, 3); /* pad */ - in_uint16_le(s, left); - in_uint16_le(s, top); - in_uint16_le(s, right); - in_uint16_le(s, bottom); - LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_RECTANGLE16 " - "left %d, top %d, right %d, bottom %d", - left, top, right, bottom); - if (self->session->callback != 0) - { - self->session->callback(self->session->id, 0x5559, 0, - MAKELONG(left, top), - MAKELONG(right, bottom), 0); - } - else - { - LOG_DEVEL(LOG_LEVEL_WARNING, - "Bug: no callback registered for xrdp_rdp_process_suppress"); - } - break; - } - return 0; + return rv; } /*****************************************************************************/ diff --git a/vnc/vnc.c b/vnc/vnc.c index 6a72834a..77845e2f 100644 --- a/vnc/vnc.c +++ b/vnc/vnc.c @@ -1249,6 +1249,12 @@ lib_framebuffer_waiting_for_resize_confirm(struct vnc *v) { LOG(LOG_LEVEL_DEBUG, "VNC server successfully resized"); log_screen_layout(LOG_LEVEL_INFO, "NewLayout", &layout); + // If this resize was requested by the client mid-session + // (dynamic resize), we need to tell xrdp_mm that + // it's OK to continue with the resize state machine. + // We do this by sending a reset with bpp == 0 + error = v->server_reset(v, v->server_width, + v->server_height, 0); } else { diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 00843fa9..4fc8a808 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -471,6 +471,9 @@ struct display_control_monitor_layout_data enum display_resize_state state; int last_state_update_timestamp; int start_time; + /// This flag is set if the state machine needs to + /// shutdown/startup EGFX + int using_egfx; }; int @@ -478,6 +481,8 @@ xrdp_mm_drdynvc_up(struct xrdp_mm *self); int xrdp_mm_suppress_output(struct xrdp_mm *self, int suppress, int left, int top, int right, int bottom); +int +xrdp_mm_up_and_running(struct xrdp_mm *self); struct xrdp_mm * xrdp_mm_create(struct xrdp_wm *owner); void diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 6d6279f1..0203b0bf 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -1541,10 +1541,11 @@ dynamic_monitor_data(intptr_t id, int chan_id, char *data, int bytes) pro = (struct xrdp_process *) id; wm = pro->wm; - if (wm->client_info->suppress_output == 1) + if (OUTPUT_SUPPRESSED_FOR_REASON(wm->client_info, + XSO_REASON_CLIENT_REQUEST)) { LOG(LOG_LEVEL_INFO, "dynamic_monitor_data: Not allowing resize." - " Suppress output is active."); + " Suppress output requested by client"); return error; } @@ -1664,13 +1665,18 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) switch (description->state) { case WMRZ_ENCODER_DELETE: + // Stop any output from the module + rdp = (struct xrdp_rdp *) (wm->session->rdp); + xrdp_rdp_suppress_output(rdp, + 1, XSO_REASON_DYNAMIC_RESIZE, + 0, 0, 0, 0); // Disable the encoder until the resize is complete. if (mm->encoder != NULL) { xrdp_encoder_delete(mm->encoder); mm->encoder = NULL; } - if (mm->egfx == 0) + if (mm->resize_data->using_egfx == 0) { advance_resize_state_machine(mm, WMRZ_SERVER_MONITOR_RESIZE); } @@ -1695,7 +1701,7 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) break; // Also processed in xrdp_egfx_close_response case WMRZ_EGFX_CONN_CLOSING: - rdp = (struct xrdp_rdp *) (mm->wm->session->rdp); + rdp = (struct xrdp_rdp *) (wm->session->rdp); sec = rdp->sec_layer; chan = sec->chan_layer; @@ -1750,9 +1756,9 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) // Not processed here. Processed in server_reset // case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING: case WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED: - advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESIZE); + advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESET); break; - case WMRZ_XRDP_CORE_RESIZE: + case WMRZ_XRDP_CORE_RESET: // TODO: Unify this logic with server_reset error = libxrdp_reset( wm->session, desc_width, desc_height, wm->screen->bpp); @@ -1772,6 +1778,12 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) " xrdp_cache_reset failed %d", error); return advance_error(error, mm); } + advance_resize_state_machine(mm, WMRZ_XRDP_CORE_RESET_PROCESSING); + break; + + // Not processed here. Processed in xrdp_mm_up_and_running() + // case WMRZ_XRDP_CORE_RESET_PROCESSING: + case WMRZ_XRDP_CORE_RESET_PROCESSED: /* load some stuff */ error = xrdp_wm_load_static_colors_plus(wm, 0); if (error != 0) @@ -1804,7 +1816,7 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) advance_resize_state_machine(mm, WMRZ_EGFX_INITIALIZE); break; case WMRZ_EGFX_INITIALIZE: - if (error == 0 && mm->egfx == NULL && mm->egfx_up == 0) + if (mm->resize_data->using_egfx) { egfx_initialize(mm); advance_resize_state_machine(mm, WMRZ_EGFX_INITALIZING); @@ -1827,6 +1839,16 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) advance_resize_state_machine(mm, WMRZ_SERVER_INVALIDATE); break; case WMRZ_SERVER_INVALIDATE: + if (module != 0) + { + // Ack all frames to speed up resize. + module->mod_frame_ack(module, 0, INT_MAX); + } + // Restart module output + rdp = (struct xrdp_rdp *) (wm->session->rdp); + xrdp_rdp_suppress_output(rdp, + 0, XSO_REASON_DYNAMIC_RESIZE, + 0, 0, desc_width, desc_height); /* redraw */ error = xrdp_bitmap_invalidate(wm->screen, 0); if (error != 0) @@ -1836,11 +1858,6 @@ process_display_control_monitor_layout_data(struct xrdp_wm *wm) " xrdp_bitmap_invalidate failed %d", error); return advance_error(error, mm); } - if (module != 0) - { - // Ack all frames to speed up resize. - module->mod_frame_ack(module, 0, INT_MAX); - } advance_resize_state_machine(mm, WMRZ_COMPLETE); break; default: @@ -1920,6 +1937,7 @@ dynamic_monitor_process_queue(struct xrdp_mm *self) const int time = g_time3(); self->resize_data->start_time = time; self->resize_data->last_state_update_timestamp = time; + self->resize_data->using_egfx = (self->egfx != NULL); advance_resize_state_machine(self, WMRZ_ENCODER_DELETE); } else @@ -2067,6 +2085,21 @@ xrdp_mm_suppress_output(struct xrdp_mm *self, int suppress, return 0; } +/******************************************************************************/ +int +xrdp_mm_up_and_running(struct xrdp_mm *self) +{ + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_up_and_running:"); + if (self->resize_data != NULL && + self->resize_data->state == WMRZ_XRDP_CORE_RESET_PROCESSING) + { + LOG(LOG_LEVEL_INFO, + "xrdp_mm_up_and_running: Core reset done."); + advance_resize_state_machine(self, WMRZ_XRDP_CORE_RESET_PROCESSED); + } + return 0; +} + /*****************************************************************************/ /* open response from client going to channel server */ static int diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 06ccf446..a066980f 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -347,7 +347,9 @@ enum display_resize_state WMRZ_SERVER_VERSION_MESSAGE_START, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED, - WMRZ_XRDP_CORE_RESIZE, + WMRZ_XRDP_CORE_RESET, + WMRZ_XRDP_CORE_RESET_PROCESSING, + WMRZ_XRDP_CORE_RESET_PROCESSED, WMRZ_EGFX_INITIALIZE, WMRZ_EGFX_INITALIZING, WMRZ_EGFX_INITIALIZED, @@ -371,7 +373,11 @@ enum display_resize_state "WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING" : \ (status) == WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED ? \ "WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED" : \ - (status) == WMRZ_XRDP_CORE_RESIZE ? "WMRZ_XRDP_CORE_RESIZE" : \ + (status) == WMRZ_XRDP_CORE_RESET ? "WMRZ_XRDP_CORE_RESET" : \ + (status) == WMRZ_XRDP_CORE_RESET_PROCESSING ? \ + "WMRZ_XRDP_CORE_RESET_PROCESSING" : \ + (status) == WMRZ_XRDP_CORE_RESET_PROCESSED ? \ + "WMRZ_XRDP_CORE_RESET_PROCESSED" : \ (status) == WMRZ_EGFX_INITIALIZE ? "WMRZ_EGFX_INITIALIZE" : \ (status) == WMRZ_EGFX_INITALIZING ? "WMRZ_EGFX_INITALIZING" : \ (status) == WMRZ_EGFX_INITIALIZED ? "WMRZ_EGFX_INITIALIZED" : \ diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c index 8d0a48c3..fcf59e55 100644 --- a/xrdp/xrdp_wm.c +++ b/xrdp/xrdp_wm.c @@ -2029,6 +2029,9 @@ callback(intptr_t id, int msg, intptr_t param1, intptr_t param2, xrdp_mm_suppress_output(wm->mm, param1, LOWORD(param2), HIWORD(param2), LOWORD(param3), HIWORD(param3)); + case 0x555a: + // "yeah, up_and_running" + xrdp_mm_up_and_running(wm->mm); break; } return rv; From 33539c1d8bc7a2c290cf43350314b0c24ebec778 Mon Sep 17 00:00:00 2001 From: jsorg71 Date: Thu, 1 Feb 2024 07:28:30 -0800 Subject: [PATCH 18/21] Gfx mainline merge multimon1 (#2933) * GFX: work on multimon * fix for non GFX multimon --- xrdp/xrdp.h | 4 + xrdp/xrdp_encoder.c | 621 ++++++++++++++++++++++++++++++++++++++++---- xrdp/xrdp_encoder.h | 58 ++++- xrdp/xrdp_mm.c | 175 ++++++++----- xrdp/xrdp_types.h | 5 +- xup/xup.c | 55 ++++ xup/xup.h | 5 +- 7 files changed, 789 insertions(+), 134 deletions(-) diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 4fc8a808..6c1c4e0c 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -652,5 +652,9 @@ server_add_char_alpha(struct xrdp_mod *mod, int font, int character, int width, int height, char *data); int server_session_info(struct xrdp_mod *mod, const char *data, int data_bytes); +int +server_egfx_cmd(struct xrdp_mod *v, + char *cmd, int cmd_bytes, + char *data, int data_bytes); #endif diff --git a/xrdp/xrdp_encoder.c b/xrdp/xrdp_encoder.c index 3eb75699..fb89b346 100644 --- a/xrdp/xrdp_encoder.c +++ b/xrdp/xrdp_encoder.c @@ -27,6 +27,7 @@ #include "ms-rdpbcgr.h" #include "thread_calls.h" #include "fifo.h" +#include "xrdp_egfx.h" #ifdef XRDP_RFXCODEC #include "rfxcodec_encode.h" @@ -44,12 +45,22 @@ static const unsigned char g_rfx_quantization_values[] = }; #endif +struct enc_rect +{ + short x1; + short y1; + short x2; + short y2; +}; + /*****************************************************************************/ static int process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc); #ifdef XRDP_RFXCODEC static int process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc); +static int +process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc); #endif static int process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc); @@ -60,8 +71,8 @@ static void xrdp_enc_data_destructor(void *item, void *closure) { XRDP_ENC_DATA *enc = (XRDP_ENC_DATA *)item; - g_free(enc->drects); - g_free(enc->crects); + g_free(enc->u.sc.drects); + g_free(enc->u.sc.crects); g_free(enc); } @@ -123,19 +134,14 @@ xrdp_encoder_create(struct xrdp_mm *mm) LOG(LOG_LEVEL_INFO, "xrdp_encoder_create: starting gfx rfx pro codec session"); self->in_codec_mode = 1; - client_info->capture_code = 2; - self->process_enc = process_enc_rfx; + client_info->capture_code = 4; + self->process_enc = process_enc_egfx; self->gfx = 1; self->quants = (const char *) g_rfx_quantization_values; self->num_quants = 2; self->quant_idx_y = 0; self->quant_idx_u = 1; self->quant_idx_v = 1; - self->codec_handle = rfxcodec_encode_create( - mm->wm->screen->width, - mm->wm->screen->height, - RFX_FORMAT_YUV, - RFX_FLAGS_RLGR1 | RFX_FLAGS_PRO1); } else if (client_info->rfx_codec_id != 0) { @@ -144,9 +150,9 @@ xrdp_encoder_create(struct xrdp_mm *mm) self->in_codec_mode = 1; client_info->capture_code = 2; self->process_enc = process_enc_rfx; - self->codec_handle = rfxcodec_encode_create(mm->wm->screen->width, - mm->wm->screen->height, - RFX_FORMAT_YUV, 0); + self->codec_handle_rfx = rfxcodec_encode_create(mm->wm->screen->width, + mm->wm->screen->height, + RFX_FORMAT_YUV, 0); } #endif else if (client_info->h264_codec_id != 0) @@ -205,6 +211,10 @@ xrdp_encoder_create(struct xrdp_mm *mm) void xrdp_encoder_delete(struct xrdp_encoder *self) { + int index; + + (void)index; + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_encoder_delete:"); if (self == 0) { @@ -218,15 +228,31 @@ xrdp_encoder_delete(struct xrdp_encoder *self) g_set_wait_obj(self->xrdp_encoder_term); g_sleep(1000); - /* todo delete specific encoder */ - - if (self->process_enc == process_enc_jpg) - { - } #ifdef XRDP_RFXCODEC - else if (self->process_enc == process_enc_rfx) + for (index = 0; index < 16; index++) { - rfxcodec_encode_destroy(self->codec_handle); + if (self->codec_handle_prfx_gfx[index] != NULL) + { + rfxcodec_encode_destroy(self->codec_handle_prfx_gfx[index]); + } + } + if (self->codec_handle_rfx != NULL) + { + rfxcodec_encode_destroy(self->codec_handle_rfx); + } +#endif + +#if defined(XRDP_X264) + for (index = 0; index < 16; index++) + { + if (self->codec_handle_h264_gfx[index] != NULL) + { + rfxcodec_encode_destroy(self->codec_handle_h264_gfx[index]); + } + } + if (self->codec_handle_h264 != NULL) + { + xrdp_encoder_x264_delete(self->codec_handle_h264); } #endif @@ -267,13 +293,13 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) fifo_processed = self->fifo_processed; mutex = self->mutex; event_processed = self->xrdp_encoder_event_processed; - count = enc->num_crects; + count = enc->u.sc.num_crects; for (index = 0; index < count; index++) { - x = enc->crects[index * 4 + 0]; - y = enc->crects[index * 4 + 1]; - cx = enc->crects[index * 4 + 2]; - cy = enc->crects[index * 4 + 3]; + x = enc->u.sc.crects[index * 4 + 0]; + y = enc->u.sc.crects[index * 4 + 1]; + cx = enc->u.sc.crects[index * 4 + 2]; + cy = enc->u.sc.crects[index * 4 + 3]; if (cx < 1 || cy < 1) { LOG_DEVEL(LOG_LEVEL_WARNING, "process_enc_jpg: error 1"); @@ -300,9 +326,9 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) out_data[256] = 0; /* header bytes */ out_data[257] = 0; - error = libxrdp_codec_jpeg_compress(self->mm->wm->session, 0, enc->data, - enc->width, enc->height, - enc->width * 4, x, y, cx, cy, + error = libxrdp_codec_jpeg_compress(self->mm->wm->session, 0, enc->u.sc.data, + enc->u.sc.width, enc->u.sc.height, + enc->u.sc.width * 4, x, y, cx, cy, quality, out_data + XRDP_SURCMD_PREFIX_BYTES + 2, @@ -322,7 +348,7 @@ process_enc_jpg(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) enc_done->pad_bytes = 256; enc_done->comp_pad_data = out_data; enc_done->enc = enc; - enc_done->last = index == (enc->num_crects - 1); + enc_done->last = index == (enc->u.sc.num_crects - 1); enc_done->x = x; enc_done->y = y; enc_done->cx = cx; @@ -368,7 +394,7 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) LOG_DEVEL(LOG_LEVEL_DEBUG, "process_enc_rfx:"); LOG_DEVEL(LOG_LEVEL_DEBUG, "process_enc_rfx: num_crects %d num_drects %d", - enc->num_crects, enc->num_drects); + enc->u.sc.num_crects, enc->u.sc.num_drects); fifo_processed = self->fifo_processed; mutex = self->mutex; event_processed = self->xrdp_encoder_event_processed; @@ -378,16 +404,16 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) do { tiles_written = 0; - tiles_left = enc->num_crects - all_tiles_written; + tiles_left = enc->u.sc.num_crects - all_tiles_written; out_data = NULL; out_data_bytes = 0; - if ((tiles_left > 0) && (enc->num_drects > 0)) + if ((tiles_left > 0) && (enc->u.sc.num_drects > 0)) { alloc_bytes = XRDP_SURCMD_PREFIX_BYTES; alloc_bytes += self->max_compressed_bytes; alloc_bytes += sizeof(struct rfx_tile) * tiles_left + - sizeof(struct rfx_rect) * enc->num_drects; + sizeof(struct rfx_rect) * enc->u.sc.num_drects; out_data = g_new(char, alloc_bytes); if (out_data != NULL) { @@ -399,10 +425,10 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) count = tiles_left; for (index = 0; index < count; index++) { - x = enc->crects[(index + all_tiles_written) * 4 + 0]; - y = enc->crects[(index + all_tiles_written) * 4 + 1]; - cx = enc->crects[(index + all_tiles_written) * 4 + 2]; - cy = enc->crects[(index + all_tiles_written) * 4 + 3]; + x = enc->u.sc.crects[(index + all_tiles_written) * 4 + 0]; + y = enc->u.sc.crects[(index + all_tiles_written) * 4 + 1]; + cx = enc->u.sc.crects[(index + all_tiles_written) * 4 + 2]; + cy = enc->u.sc.crects[(index + all_tiles_written) * 4 + 3]; tiles[index].x = x; tiles[index].y = y; tiles[index].cx = cx; @@ -412,13 +438,13 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) tiles[index].quant_cr = self->quant_idx_v; } - count = enc->num_drects; + count = enc->u.sc.num_drects; for (index = 0; index < count; index++) { - x = enc->drects[index * 4 + 0]; - y = enc->drects[index * 4 + 1]; - cx = enc->drects[index * 4 + 2]; - cy = enc->drects[index * 4 + 3]; + x = enc->u.sc.drects[index * 4 + 0]; + y = enc->u.sc.drects[index * 4 + 1]; + cx = enc->u.sc.drects[index * 4 + 2]; + cy = enc->u.sc.drects[index * 4 + 3]; rfxrects[index].x = x; rfxrects[index].y = y; rfxrects[index].cx = cx; @@ -432,13 +458,13 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) { encode_flags = RFX_FLAGS_PRO_KEY; } - tiles_written = rfxcodec_encode_ex(self->codec_handle, + tiles_written = rfxcodec_encode_ex(self->codec_handle_rfx, out_data + XRDP_SURCMD_PREFIX_BYTES, - &out_data_bytes, enc->data, - enc->width, enc->height, - enc->width * 4, - rfxrects, enc->num_drects, - tiles, enc->num_crects, + &out_data_bytes, enc->u.sc.data, + enc->u.sc.width, enc->u.sc.height, + ((enc->u.sc.width + 63) & ~63) * 4, + rfxrects, enc->u.sc.num_drects, + tiles, enc->u.sc.num_crects, self->quants, self->num_quants, encode_flags); } @@ -460,20 +486,18 @@ process_enc_rfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) enc_done->pad_bytes = XRDP_SURCMD_PREFIX_BYTES; enc_done->comp_pad_data = out_data; enc_done->enc = enc; - enc_done->cx = self->mm->wm->screen->width; - enc_done->cy = self->mm->wm->screen->height; - if (self->gfx) - { - enc_done->flags = (enum xrdp_encoder_flags) - ((int)enc_done->flags | GFX_PROGRESSIVE_RFX); - } + enc_done->x = enc->u.sc.left; + enc_done->y = enc->u.sc.top; + enc_done->cx = enc->u.sc.width; + enc_done->cy = enc->u.sc.height; + enc_done->frame_id = enc->u.sc.frame_id; enc_done->continuation = all_tiles_written > 0; if (tiles_written > 0) { all_tiles_written += tiles_written; } finished = - (all_tiles_written == enc->num_crects) || (tiles_written < 0); + (all_tiles_written == enc->u.sc.num_crects) || (tiles_written < 0); enc_done->last = finished; /* done with msg */ @@ -500,6 +524,493 @@ process_enc_h264(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) return 0; } +#ifdef XRDP_RFXCODEC + +/*****************************************************************************/ +static struct stream * +gfx_wiretosurface1(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s, + struct xrdp_enc_gfx_cmd *enc_gfx_cmd) +{ + (void)self; + (void)bulk; + (void)in_s; + (void)enc_gfx_cmd; + return NULL; +} + +/*****************************************************************************/ +static struct stream * +gfx_wiretosurface2(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s, + struct xrdp_enc_gfx_cmd *enc_gfx_cmd) +{ + int index; + int surface_id; + int codec_id; + int codec_context_id; + int pixel_format; + int num_rects_d; + int num_rects_c; + struct stream *rv; + short left; + short top; + short width; + short height; + char *bitmap_data; + int bitmap_data_length; + struct rfx_tile *tiles; + struct rfx_rect *rfxrects; + int flags; + int tiles_written; + int do_free; + int do_send; + int mon_index; + + if (!s_check_rem(in_s, 15)) + { + return NULL; + } + in_uint16_le(in_s, surface_id); + in_uint16_le(in_s, codec_id); + in_uint32_le(in_s, codec_context_id); + in_uint8(in_s, pixel_format); + in_uint32_le(in_s, flags); + mon_index = (flags >> 28) & 0xF; + in_uint16_le(in_s, num_rects_d); + if ((num_rects_d < 1) || (num_rects_d > 16 * 1024) || + (!s_check_rem(in_s, num_rects_d * 8))) + { + return NULL; + } + rfxrects = g_new0(struct rfx_rect, num_rects_d); + if (rfxrects == NULL) + { + return NULL; + } + for (index = 0; index < num_rects_d; index++) + { + in_uint16_le(in_s, left); + in_uint16_le(in_s, top); + in_uint16_le(in_s, width); + in_uint16_le(in_s, height); + rfxrects[index].x = left; + rfxrects[index].y = top; + rfxrects[index].cx = width; + rfxrects[index].cy = height; + } + if (!s_check_rem(in_s, 2)) + { + g_free(rfxrects); + return NULL; + } + in_uint16_le(in_s, num_rects_c); + if ((num_rects_c < 1) || (num_rects_c > 16 * 1024) || + (!s_check_rem(in_s, num_rects_c * 8))) + { + g_free(rfxrects); + return NULL; + } + tiles = g_new0(struct rfx_tile, num_rects_c); + if (tiles == NULL) + { + g_free(rfxrects); + return NULL; + } + for (index = 0; index < num_rects_c; index++) + { + in_uint16_le(in_s, left); + in_uint16_le(in_s, top); + in_uint16_le(in_s, width); + in_uint16_le(in_s, height); + tiles[index].x = left; + tiles[index].y = top; + tiles[index].cx = width; + tiles[index].cy = height; + tiles[index].quant_y = self->quant_idx_y; + tiles[index].quant_cb = self->quant_idx_u; + tiles[index].quant_cr = self->quant_idx_v; + } + if (!s_check_rem(in_s, 8)) + { + g_free(tiles); + g_free(rfxrects); + return NULL; + } + in_uint16_le(in_s, left); + in_uint16_le(in_s, top); + in_uint16_le(in_s, width); + in_uint16_le(in_s, height); + if (self->codec_handle_prfx_gfx[mon_index] == NULL) + { + self->codec_handle_prfx_gfx[mon_index] = rfxcodec_encode_create( + width, + height, + RFX_FORMAT_YUV, + RFX_FLAGS_RLGR1 | RFX_FLAGS_PRO1); + if (self->codec_handle_prfx_gfx[mon_index] == NULL) + { + return NULL; + } + } + + do_free = 0; + do_send = 0; + if (ENC_IS_BIT_SET(flags, 0)) + { + /* already compressed */ + bitmap_data_length = enc_gfx_cmd->data_bytes; + bitmap_data = enc_gfx_cmd->data; + do_send = 1; + } + else + { + bitmap_data_length = self->max_compressed_bytes; + bitmap_data = g_new(char, bitmap_data_length); + if (bitmap_data == NULL) + { + g_free(tiles); + g_free(rfxrects); + return NULL; + } + do_free = 1; + tiles_written = rfxcodec_encode(self->codec_handle_prfx_gfx[mon_index], + bitmap_data, + &bitmap_data_length, + enc_gfx_cmd->data, + width, height, + ((width + 63) & ~63) * 4, + rfxrects, num_rects_d, + tiles, num_rects_c, + self->quants, self->num_quants); + if (tiles_written > 0) + { + do_send = 1; + } + } + g_free(tiles); + g_free(rfxrects); + rv = NULL; + if (do_send) + { + rv = xrdp_egfx_wire_to_surface2(bulk, surface_id, + codec_id, codec_context_id, + pixel_format, + bitmap_data, bitmap_data_length); + } + if (do_free) + { + g_free(bitmap_data); + } + return rv; +} + +/*****************************************************************************/ +static struct stream * +gfx_solidfill(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s) +{ + int surface_id; + int pixel; + int num_rects; + char *ptr8; + struct xrdp_egfx_rect *rects; + + if (!s_check_rem(in_s, 8)) + { + return NULL; + } + in_uint16_le(in_s, surface_id); + in_uint32_le(in_s, pixel); + in_uint16_le(in_s, num_rects); + if (!s_check_rem(in_s, num_rects * 8)) + { + return NULL; + } + in_uint8p(in_s, ptr8, num_rects * 8); + rects = (struct xrdp_egfx_rect *) ptr8; + return xrdp_egfx_fill_surface(bulk, surface_id, pixel, num_rects, rects); +} + +/*****************************************************************************/ +static struct stream * +gfx_surfacetosurface(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s) +{ + int surface_id_src; + int surface_id_dst; + char *ptr8; + int num_pts; + struct xrdp_egfx_rect *rects; + struct xrdp_egfx_point *pts; + + if (!s_check_rem(in_s, 14)) + { + return NULL; + } + in_uint16_le(in_s, surface_id_src); + in_uint16_le(in_s, surface_id_dst); + in_uint8p(in_s, ptr8, 8); + rects = (struct xrdp_egfx_rect *) ptr8; + in_uint16_le(in_s, num_pts); + if (!s_check_rem(in_s, num_pts * 4)) + { + return NULL; + } + in_uint8p(in_s, ptr8, num_pts * 4); + pts = (struct xrdp_egfx_point *) ptr8; + return xrdp_egfx_surface_to_surface(bulk, surface_id_src, surface_id_dst, + rects, num_pts, pts); +} + +/*****************************************************************************/ +static struct stream * +gfx_createsurface(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s) +{ + int surface_id; + int width; + int height; + int pixel_format; + + if (!s_check_rem(in_s, 7)) + { + return NULL; + } + in_uint16_le(in_s, surface_id); + in_uint16_le(in_s, width); + in_uint16_le(in_s, height); + in_uint8(in_s, pixel_format); + return xrdp_egfx_create_surface(bulk, surface_id, + width, height, pixel_format); +} + +/*****************************************************************************/ +static struct stream * +gfx_deletesurface(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s) +{ + int surface_id; + + if (!s_check_rem(in_s, 2)) + { + return NULL; + } + in_uint16_le(in_s, surface_id); + return xrdp_egfx_delete_surface(bulk, surface_id); +} + +/*****************************************************************************/ +static struct stream * +gfx_startframe(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s) +{ + int frame_id; + int time_stamp; + + if (!s_check_rem(in_s, 8)) + { + return NULL; + } + in_uint32_le(in_s, frame_id); + in_uint32_le(in_s, time_stamp); + return xrdp_egfx_frame_start(bulk, frame_id, time_stamp); +} + +/*****************************************************************************/ +static struct stream * +gfx_endframe(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s, int *aframe_id) +{ + int frame_id; + + if (!s_check_rem(in_s, 4)) + { + return NULL; + } + in_uint32_le(in_s, frame_id); + *aframe_id = frame_id; + return xrdp_egfx_frame_end(bulk, frame_id); +} + +/*****************************************************************************/ +static struct stream * +gfx_resetgraphics(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s) +{ + int width; + int height; + int monitor_count; + int index; + struct monitor_info *mi; + struct stream *rv; + + if (!s_check_rem(in_s, 12)) + { + return NULL; + } + in_uint32_le(in_s, width); + in_uint32_le(in_s, height); + in_uint32_le(in_s, monitor_count); + if ((monitor_count < 1) || (monitor_count > 16) || + !s_check_rem(in_s, monitor_count * 20)) + { + return NULL; + } + mi = g_new0(struct monitor_info, monitor_count); + if (mi == NULL) + { + return NULL; + } + for (index = 0; index < monitor_count; index++) + { + in_uint32_le(in_s, mi[index].left); + in_uint32_le(in_s, mi[index].top); + in_uint32_le(in_s, mi[index].right); + in_uint32_le(in_s, mi[index].bottom); + in_uint32_le(in_s, mi[index].is_primary); + } + rv = xrdp_egfx_reset_graphics(bulk, width, height, monitor_count, mi); + g_free(mi); + return rv; +} + +/*****************************************************************************/ +static struct stream * +gfx_mapsurfacetooutput(struct xrdp_encoder *self, + struct xrdp_egfx_bulk *bulk, struct stream *in_s) +{ + int surface_id; + int x; + int y; + + if (!s_check_rem(in_s, 10)) + { + return NULL; + } + in_uint16_le(in_s, surface_id); + in_uint32_le(in_s, x); + in_uint32_le(in_s, y); + return xrdp_egfx_map_surface(bulk, surface_id, x, y); +} + +/*****************************************************************************/ +/* called from encoder thread */ +static int +process_enc_egfx(struct xrdp_encoder *self, XRDP_ENC_DATA *enc) +{ + struct stream *s; + struct stream in_s; + struct xrdp_egfx_bulk *bulk; + XRDP_ENC_DATA_DONE *enc_done; + struct fifo *fifo_processed; + tbus mutex; + tbus event_processed; + int cmd_id; + int cmd_bytes; + int frame_id; + int got_frame_id; + char *holdp; + char *holdend; + + fifo_processed = self->fifo_processed; + mutex = self->mutex; + event_processed = self->xrdp_encoder_event_processed; + bulk = self->mm->egfx->bulk; + g_memset(&in_s, 0, sizeof(in_s)); + in_s.data = enc->u.gfx.cmd; + in_s.size = enc->u.gfx.cmd_bytes; + in_s.p = in_s.data; + in_s.end = in_s.data + in_s.size; + while (s_check_rem(&in_s, 8)) + { + s = NULL; + frame_id = 0; + got_frame_id = 0; + holdp = in_s.p; + in_uint16_le(&in_s, cmd_id); + in_uint8s(&in_s, 2); /* flags */ + in_uint32_le(&in_s, cmd_bytes); + if ((cmd_bytes < 8) || (cmd_bytes > 32 * 1024)) + { + return 1; + } + holdend = in_s.end; + in_s.end = holdp + cmd_bytes; + switch (cmd_id) + { + case XR_RDPGFX_CMDID_WIRETOSURFACE_1: /* 0x0001 */ + s = gfx_wiretosurface1(self, bulk, &in_s, &(enc->u.gfx)); + break; + case XR_RDPGFX_CMDID_WIRETOSURFACE_2: /* 0x0002 */ + s = gfx_wiretosurface2(self, bulk, &in_s, &(enc->u.gfx)); + break; + case XR_RDPGFX_CMDID_SOLIDFILL: /* 0x0004 */ + s = gfx_solidfill(self, bulk, &in_s); + break; + case XR_RDPGFX_CMDID_SURFACETOSURFACE: /* 0x0005 */ + s = gfx_surfacetosurface(self, bulk, &in_s); + break; + case XR_RDPGFX_CMDID_CREATESURFACE: /* 0x0009 */ + s = gfx_createsurface(self, bulk, &in_s); + break; + case XR_RDPGFX_CMDID_DELETESURFACE: /* 0x000A */ + s = gfx_deletesurface(self, bulk, &in_s); + break; + case XR_RDPGFX_CMDID_STARTFRAME: /* 0x000B */ + s = gfx_startframe(self, bulk, &in_s); + break; + case XR_RDPGFX_CMDID_ENDFRAME: /* 0x000C */ + s = gfx_endframe(self, bulk, &in_s, &frame_id); + got_frame_id = 1; + break; + case XR_RDPGFX_CMDID_RESETGRAPHICS: /* 0x000E */ + s = gfx_resetgraphics(self, bulk, &in_s); + break; + case XR_RDPGFX_CMDID_MAPSURFACETOOUTPUT: /* 0x000F */ + s = gfx_mapsurfacetooutput(self, bulk, &in_s); + break; + default: + break; + } + if (s == NULL) + { + LOG(LOG_LEVEL_ERROR, "process_enc_egfx: cmd_id %d s = nil", cmd_id); + return 1; + } + /* setup for next cmd */ + in_s.p = holdp + cmd_bytes; + in_s.end = holdend; + /* setup enc_done struct */ + enc_done = g_new0(XRDP_ENC_DATA_DONE, 1); + if (enc_done == NULL) + { + free_stream(s); + return 1; + } + ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_GFX_BIT); + enc_done->enc = enc; + enc_done->last = !s_check_rem(&in_s, 8); + enc_done->comp_bytes = (int) (s->end - s->data); + enc_done->comp_pad_data = s->data; + if (got_frame_id) + { + ENC_SET_BIT(enc_done->flags, ENC_DONE_FLAGS_FRAME_ID_BIT); + enc_done->frame_id = frame_id; + } + g_free(s); /* don't call free_stream() here so s->data is valid */ + /* inform main thread done */ + tc_mutex_lock(mutex); + fifo_add_item(fifo_processed, enc_done); + tc_mutex_unlock(mutex); + /* signal completion for main thread */ + g_set_wait_obj(event_processed); + } + return 0; +} + +#endif + /** * Encoder thread main loop *****************************************************************************/ diff --git a/xrdp/xrdp_encoder.h b/xrdp/xrdp_encoder.h index a5c32a58..8dc1311b 100644 --- a/xrdp/xrdp_encoder.h +++ b/xrdp/xrdp_encoder.h @@ -3,8 +3,14 @@ #define _XRDP_ENCODER_H #include "arch.h" +#include "fifo.h" #include "xrdp_client_info.h" -struct fifo; + +#define ENC_IS_BIT_SET(_flags, _bit) (((_flags) & (1 << (_bit))) != 0) +#define ENC_SET_BIT(_flags, _bit) do { _flags |= (1 << (_bit)); } while (0) +#define ENC_CLR_BIT(_flags, _bit) do { _flags &= ~(1 << (_bit)); } while (0) +#define ENC_SET_BITS(_flags, _mask, _bits) \ + do { _flags &= ~(_mask); _flags |= (_bits) & (_mask); } while (0) struct xrdp_enc_data; @@ -23,7 +29,11 @@ struct xrdp_encoder struct fifo *fifo_processed; tbus mutex; int (*process_enc)(struct xrdp_encoder *self, struct xrdp_enc_data *enc); - void *codec_handle; + void *codec_handle_rfx; + void *codec_handle_jpg; + void *codec_handle_h264; + void *codec_handle_prfx_gfx[16]; + void *codec_handle_h264_gfx[16]; int frame_id_client; /* last frame id received from client */ int frame_id_server; /* last frame id received from Xorg */ int frame_id_server_sent; @@ -37,14 +47,16 @@ struct xrdp_encoder int quant_idx_v; }; -/* used when scheduling tasks in xrdp_encoder.c */ -struct xrdp_enc_data +/* cmd_id = 0 */ +struct xrdp_enc_surface_command { struct xrdp_mod *mod; int num_drects; - short *drects; /* 4 * num_drects */ + int pad0; + short *drects; /* 4 * num_drects */ int num_crects; - short *crects; /* 4 * num_crects */ + int pad1; + short *crects; /* 4 * num_crects */ char *data; int left; int top; @@ -52,12 +64,21 @@ struct xrdp_enc_data int height; int flags; int frame_id; - void *shmem_ptr; - int shmem_bytes; +}; + +struct xrdp_enc_gfx_cmd +{ + char *cmd; + char *data; + int cmd_bytes; + int data_bytes; }; typedef struct xrdp_enc_data XRDP_ENC_DATA; +#define ENC_DONE_FLAGS_GFX_BIT 0 +#define ENC_DONE_FLAGS_FRAME_ID_BIT 1 + /* used when scheduling tasks from xrdp_encoder.c */ struct xrdp_enc_data_done { @@ -71,7 +92,26 @@ struct xrdp_enc_data_done int y; int cx; int cy; - enum xrdp_encoder_flags flags; + int flags; /* ENC_DONE_FLAGS_* */ + int frame_id; +}; + +#define ENC_FLAGS_GFX_BIT 0 + +/* used when scheduling tasks in xrdp_encoder.c */ +struct xrdp_enc_data +{ + struct xrdp_mod *mod; + int flags; /* ENC_FLAGS_* */ + int pad0; + void *shmem_ptr; + int shmem_bytes; + int pad1; + union _u + { + struct xrdp_enc_surface_command sc; + struct xrdp_enc_gfx_cmd gfx; + } u; }; typedef struct xrdp_enc_data_done XRDP_ENC_DATA_DONE; diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 0203b0bf..94272395 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -419,6 +419,7 @@ xrdp_mm_setup_mod1(struct xrdp_mm *self) self->mod->server_composite = server_composite; self->mod->server_paint_rects = server_paint_rects; self->mod->server_session_info = server_session_info; + self->mod->server_egfx_cmd = server_egfx_cmd; self->mod->server_set_pointer_large = server_set_pointer_large; self->mod->server_paint_rects_ex = server_paint_rects_ex; self->mod->si = &(self->wm->session->si); @@ -3430,8 +3431,11 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) int y; int cx; int cy; + int is_gfx; + int got_frame_id; + int client_ack; - LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_process_enc_done:"); + LOG(LOG_LEVEL_TRACE, "xrdp_mm_process_enc_done:"); while (1) { @@ -3443,41 +3447,39 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) { break; } - /* do something with msg */ - LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_process_enc_done: message back bytes %d", - enc_done->comp_bytes); - x = enc_done->x; - y = enc_done->y; - cx = enc_done->cx; - cy = enc_done->cy; + is_gfx = ENC_IS_BIT_SET(enc_done->flags, ENC_DONE_FLAGS_GFX_BIT); + if (is_gfx) + { + got_frame_id = ENC_IS_BIT_SET(enc_done->flags, + ENC_DONE_FLAGS_FRAME_ID_BIT); + client_ack = self->encoder->gfx_ack_off == 0; + } + else + { + got_frame_id = 1; + client_ack = self->wm->client_info->use_frame_acks; + } + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_process_enc_done: message back " + "bytes %d", enc_done->comp_bytes); if (enc_done->comp_bytes > 0) { - LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_mm_process_enc_done: " - "x %d y %d cx %d cy %d frame_id %d use_frame_acks %d", - x, y, cx, cy, enc_done->enc->frame_id, - self->wm->client_info->use_frame_acks); - if (enc_done->flags & GFX_H264) + if (is_gfx) { - LOG(LOG_LEVEL_INFO, "GFX H264 Unimplemeted."); - } - else if (enc_done->flags & GFX_PROGRESSIVE_RFX) /* gfx progressive rfx */ - { - xrdp_egfx_send_frame_start(self->egfx, - enc_done->enc->frame_id, 0); - xrdp_egfx_send_wire_to_surface2(self->egfx, - self->egfx->surface_id, 9, 1, - XR_PIXEL_FORMAT_XRGB_8888, - enc_done->comp_pad_data - + enc_done->pad_bytes, - enc_done->comp_bytes); - xrdp_egfx_send_frame_end(self->egfx, enc_done->enc->frame_id); + xrdp_egfx_send_data(self->egfx, + enc_done->comp_pad_data + + enc_done->pad_bytes, + enc_done->comp_bytes); } else { + x = enc_done->x; + y = enc_done->y; + cx = enc_done->cx; + cy = enc_done->cy; if (!enc_done->continuation) { libxrdp_fastpath_send_frame_marker(self->wm->session, 0, - enc_done->enc->frame_id); + enc_done->frame_id); } libxrdp_fastpath_send_surface(self->wm->session, enc_done->comp_pad_data, @@ -3489,7 +3491,7 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) if (enc_done->last) { libxrdp_fastpath_send_frame_marker(self->wm->session, 1, - enc_done->enc->frame_id); + enc_done->frame_id); } } } @@ -3498,38 +3500,28 @@ xrdp_mm_process_enc_done(struct xrdp_mm *self) { enc = enc_done->enc; LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_mm_process_enc_done: last set"); - if (enc_done->flags & GFX_H264) /* gfx */ + if (got_frame_id) { - if (self->encoder->gfx_ack_off) + if (client_ack) { - /* gfx and client turned off client frame acks */ - self->mod->mod_frame_ack(self->mod, - enc->flags, - enc->frame_id); + self->encoder->frame_id_server = enc_done->frame_id; + xrdp_mm_update_module_frame_ack(self); } else { - self->encoder->frame_id_server = enc->frame_id; - xrdp_mm_update_module_frame_ack(self); + self->mod->mod_frame_ack(self->mod, 0, + enc_done->frame_id); } } + if (is_gfx) + { + g_free(enc->u.gfx.cmd); + } else { - if (self->wm->client_info->use_frame_acks == 0) - { - /* surface commmand and client does not do frame acks */ - self->mod->mod_frame_ack(self->mod, - enc->flags, - enc->frame_id); - } - else - { - self->encoder->frame_id_server = enc_done->enc->frame_id; - xrdp_mm_update_module_frame_ack(self); - } + g_free(enc->u.sc.drects); + g_free(enc->u.sc.crects); } - g_free(enc->drects); - g_free(enc->crects); if (enc->shmem_ptr != NULL) { g_munmap(enc->shmem_ptr, enc->shmem_bytes); @@ -4013,9 +4005,9 @@ server_paint_rects_ex(struct xrdp_mod *mod, return 1; } - enc_data->drects = (short *) - g_malloc(sizeof(short) * num_drects * 4, 0); - if (enc_data->drects == 0) + enc_data->u.sc.drects = (short *) + g_malloc(sizeof(short) * num_drects * 4, 0); + if (enc_data->u.sc.drects == 0) { if (shmem_ptr != NULL) { @@ -4025,32 +4017,32 @@ server_paint_rects_ex(struct xrdp_mod *mod, return 1; } - enc_data->crects = (short *) - g_malloc(sizeof(short) * num_crects * 4, 0); - if (enc_data->crects == 0) + enc_data->u.sc.crects = (short *) + g_malloc(sizeof(short) * num_crects * 4, 0); + if (enc_data->u.sc.crects == 0) { if (shmem_ptr != NULL) { g_munmap(shmem_ptr, shmem_bytes); } - g_free(enc_data->drects); + g_free(enc_data->u.sc.drects); g_free(enc_data); return 1; } - g_memcpy(enc_data->drects, drects, sizeof(short) * num_drects * 4); - g_memcpy(enc_data->crects, crects, sizeof(short) * num_crects * 4); + g_memcpy(enc_data->u.sc.drects, drects, sizeof(short) * num_drects * 4); + g_memcpy(enc_data->u.sc.crects, crects, sizeof(short) * num_crects * 4); enc_data->mod = mod; - enc_data->num_drects = num_drects; - enc_data->num_crects = num_crects; - enc_data->data = data; - enc_data->left = left; - enc_data->top = top; - enc_data->width = width; - enc_data->height = height; - enc_data->flags = flags; - enc_data->frame_id = frame_id; + enc_data->u.sc.num_drects = num_drects; + enc_data->u.sc.num_crects = num_crects; + enc_data->u.sc.data = data; + enc_data->u.sc.left = left; + enc_data->u.sc.top = top; + enc_data->u.sc.width = width; + enc_data->u.sc.height = height; + enc_data->u.sc.flags = flags; + enc_data->u.sc.frame_id = frame_id; enc_data->shmem_ptr = shmem_ptr; enc_data->shmem_bytes = shmem_bytes; if (width == 0 || height == 0) @@ -4110,6 +4102,53 @@ server_session_info(struct xrdp_mod *mod, const char *data, int data_bytes) return libxrdp_send_session_info(wm->session, data, data_bytes); } +/*****************************************************************************/ +int +server_egfx_cmd(struct xrdp_mod *mod, + char *cmd, int cmd_bytes, + char *data, int data_bytes) +{ + XRDP_ENC_DATA *enc; + struct xrdp_wm *wm; + struct xrdp_mm *mm; + + wm = (struct xrdp_wm *)(mod->wm); + mm = wm->mm; + enc = g_new0(struct xrdp_enc_data, 1); + if (enc == NULL) + { + if (data != NULL) + { + g_munmap(data, data_bytes); + } + return 1; + } + ENC_SET_BIT(enc->flags, ENC_FLAGS_GFX_BIT); + enc->u.gfx.cmd = g_new(char, cmd_bytes); + if (enc->u.gfx.cmd == NULL) + { + if (data != NULL) + { + g_munmap(data, data_bytes); + } + g_free(enc); + return 1; + } + g_memcpy(enc->u.gfx.cmd, cmd, cmd_bytes); + enc->u.gfx.cmd_bytes = cmd_bytes; + enc->u.gfx.data = data; + enc->u.gfx.data_bytes = data_bytes; + enc->shmem_ptr = data; + enc->shmem_bytes = data_bytes; + /* insert into fifo for encoder thread to process */ + tc_mutex_lock(mm->encoder->mutex); + fifo_add_item(mm->encoder->fifo_to_proc, enc); + tc_mutex_unlock(mm->encoder->mutex); + /* signal xrdp_encoder thread */ + g_set_wait_obj(mm->encoder->xrdp_encoder_event_to_proc); + return 0; +} + /*****************************************************************************/ int server_set_pointer(struct xrdp_mod *mod, int x, int y, diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index a066980f..0d83a09b 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -182,7 +182,10 @@ struct xrdp_mod int width, int height, int flags, int frame_id, void *shmem_ptr, int shmem_bytes); - tintptr server_dumby[100 - 48]; /* align, 100 minus the number of server + int (*server_egfx_cmd)(struct xrdp_mod *v, + char *cmd, int cmd_bytes, + char *data, int data_bytes); + tintptr server_dumby[100 - 49]; /* align, 100 minus the number of server functions above */ /* common */ tintptr handle; /* pointer to self as int */ diff --git a/xup/xup.c b/xup/xup.c index 8720b005..b9c17d74 100644 --- a/xup/xup.c +++ b/xup/xup.c @@ -1233,6 +1233,58 @@ process_server_paint_rect_shmem_ex(struct mod *amod, struct stream *s) return rv; } +/******************************************************************************/ +/* return error */ +int +process_server_egfx_shmfd(struct mod *amod, struct stream *s) +{ + char *data; + char *cmd; + int rv; + int cmd_bytes; + int shmem_bytes; + int fd; + int recv_bytes; + unsigned int num_fds; + void *shmem_ptr; + char msg[4]; + + rv = 0; + in_uint32_le(s, cmd_bytes); + in_uint8p(s, cmd, cmd_bytes); + in_uint32_le(s, shmem_bytes); + if (shmem_bytes == 0) + { + return amod->server_egfx_cmd(amod, cmd, cmd_bytes, NULL, 0); + } + fd = -1; + num_fds = -1; + if (g_tcp_can_recv(amod->trans->sck, 5000) == 0) + { + return 1; + } + recv_bytes = g_sck_recv_fd_set(amod->trans->sck, msg, 4, &fd, 1, &num_fds); + LOG_DEVEL(LOG_LEVEL_DEBUG, "process_server_egfx_shmfd: " + "g_sck_recv_fd_set rv %d fd %d", recv_bytes, fd); + if (recv_bytes == 4) + { + if (num_fds == 1) + { + if (g_file_map(fd, 1, 0, shmem_bytes, &shmem_ptr) == 0) + { + /* we give up ownership of shmem_ptr + will get cleaned up in server_egfx_cmd or + xrdp_mm_process_enc_done(gfx) */ + data = (char *) shmem_ptr; + rv = amod->server_egfx_cmd(amod, cmd, cmd_bytes, + data, shmem_bytes); + } + g_file_close(fd); + } + } + return rv; +} + /******************************************************************************/ /* return error */ static int @@ -1614,6 +1666,9 @@ lib_mod_process_orders(struct mod *mod, int type, struct stream *s) case 61: /* server_paint_rect_shmem_ex */ rv = process_server_paint_rect_shmem_ex(mod, s); break; + case 62: + rv = process_server_egfx_shmfd(mod, s); + break; case 63: /* server_set_pointer_shmfd */ rv = process_server_set_pointer_shmfd(mod, s); break; diff --git a/xup/xup.h b/xup/xup.h index 41061191..c316ab14 100644 --- a/xup/xup.h +++ b/xup/xup.h @@ -167,7 +167,10 @@ struct mod int width, int height, int flags, int frame_id, void *shmem_ptr, int shmem_bytes); - tintptr server_dumby[100 - 48]; /* align, 100 minus the number of server + int (*server_egfx_cmd)(struct mod *v, + char *cmd, int cmd_bytes, + char *data, int data_bytes); + tintptr server_dumby[100 - 49]; /* align, 100 minus the number of server functions above */ /* common */ tintptr handle; /* pointer to self as long */ From 75b41afa04aa387acd569a691ca92e33107b78bd Mon Sep 17 00:00:00 2001 From: Nexarian Date: Fri, 2 Feb 2024 18:53:41 -0500 Subject: [PATCH 19/21] Fix crash with resizing --- xrdp/xrdp_mm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index 94272395..d2f0be63 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -4114,6 +4114,10 @@ server_egfx_cmd(struct xrdp_mod *mod, wm = (struct xrdp_wm *)(mod->wm); mm = wm->mm; + if (mm->encoder == NULL) + { + return 0; + } enc = g_new0(struct xrdp_enc_data, 1); if (enc == NULL) { From 8027a424979fbd1b9f6026d1fbb4bc0c76b7fb68 Mon Sep 17 00:00:00 2001 From: Nexarian Date: Fri, 2 Feb 2024 21:19:49 -0500 Subject: [PATCH 20/21] More NPE fix --- xrdp/xrdp_mm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/xrdp/xrdp_mm.c b/xrdp/xrdp_mm.c index d2f0be63..4a7e9073 100644 --- a/xrdp/xrdp_mm.c +++ b/xrdp/xrdp_mm.c @@ -4116,7 +4116,11 @@ server_egfx_cmd(struct xrdp_mod *mod, mm = wm->mm; if (mm->encoder == NULL) { - return 0; + if (data != NULL) + { + g_munmap(data, data_bytes); + } + return 1; } enc = g_new0(struct xrdp_enc_data, 1); if (enc == NULL) From 76242bbf637a5893a51188b807b8de4bac502e64 Mon Sep 17 00:00:00 2001 From: metalefty Date: Thu, 8 Feb 2024 21:09:09 +0900 Subject: [PATCH 21/21] GFX: Relegate some logs to LOG_DEVEL (#2939) --- xrdp/xrdp_egfx.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/xrdp/xrdp_egfx.c b/xrdp/xrdp_egfx.c index ca196ebe..26b09783 100644 --- a/xrdp/xrdp_egfx.c +++ b/xrdp/xrdp_egfx.c @@ -105,7 +105,7 @@ xrdp_egfx_create_surface(struct xrdp_egfx_bulk *bulk, int surface_id, int bytes; struct stream *s; - LOG(LOG_LEVEL_TRACE, "xrdp_egfx_create_surface:"); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_egfx_create_surface:"); make_stream(s); init_stream(s, 8192); /* RDP_SEGMENTED_DATA */ @@ -135,12 +135,12 @@ xrdp_egfx_send_create_surface(struct xrdp_egfx *egfx, int surface_id, int error; struct stream *s; - LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_create_surface:"); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_egfx_send_create_surface:"); s = xrdp_egfx_create_surface(egfx->bulk, surface_id, width, height, pixel_format); error = xrdp_egfx_send_s(egfx, s); - LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_create_surface: xrdp_egfx_send_s " - "error %d", error); + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_egfx_send_create_surface: xrdp_egfx_send_s " + "error %d", error); free_stream(s); return error; } @@ -181,8 +181,8 @@ xrdp_egfx_send_delete_surface(struct xrdp_egfx *egfx, int surface_id) LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_delete_surface:"); s = xrdp_egfx_delete_surface(egfx->bulk, surface_id); error = xrdp_egfx_send_s(egfx, s); - LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_delete_surface: xrdp_egfx_send_s " - "error %d", error); + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_egfx_send_delete_surface: xrdp_egfx_send_s " + "error %d", error); free_stream(s); return error; } @@ -538,16 +538,16 @@ xrdp_egfx_wire_to_surface1(struct xrdp_egfx_bulk *bulk, int surface_id, /* RDP8_BULK_ENCODED_DATA */ out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ out_uint8a(s, bitmap_data8 + index, segment_size); - LOG(LOG_LEVEL_DEBUG, " segment index %d segment_size %d", - segment_count, segment_size); + LOG_DEVEL(LOG_LEVEL_DEBUG, " segment index %d segment_size %d", + segment_count, segment_size); index += segment_size; segment_count++; } s_mark_end(s); s_pop_layer(s, iso_hdr); out_uint16_le(s, segment_count); - LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_wire_to_surface1: segment_count %d", - segment_count); + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_egfx_wire_to_surface1: segment_count %d", + segment_count); return s; } @@ -561,13 +561,13 @@ xrdp_egfx_send_wire_to_surface1(struct xrdp_egfx *egfx, int surface_id, int error; struct stream *s; - LOG(LOG_LEVEL_TRACE, "xrdp_egfx_send_wire_to_surface1:"); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_egfx_send_wire_to_surface1:"); s = xrdp_egfx_wire_to_surface1(egfx->bulk, surface_id, codec_id, pixel_format, dest_rect, bitmap_data, bitmap_data_length); error = xrdp_egfx_send_s(egfx, s); - LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_wire_to_surface1: xrdp_egfx_send_s " - "error %d", error); + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_egfx_send_wire_to_surface1: xrdp_egfx_send_s " + "error %d", error); free_stream(s); return error; } @@ -586,7 +586,7 @@ xrdp_egfx_wire_to_surface2(struct xrdp_egfx_bulk *bulk, int surface_id, struct stream *s; char *bitmap_data8; - LOG(LOG_LEVEL_TRACE, "xrdp_egfx_wire_to_surface2:"); + LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_egfx_wire_to_surface2:"); make_stream(s); bytes = bitmap_data_length + 8192; bytes += 5 * (bitmap_data_length / MAX_PART_SIZE); @@ -623,16 +623,16 @@ xrdp_egfx_wire_to_surface2(struct xrdp_egfx_bulk *bulk, int surface_id, /* RDP8_BULK_ENCODED_DATA */ out_uint8(s, PACKET_COMPR_TYPE_RDP8); /* header */ out_uint8a(s, bitmap_data8 + index, segment_size); - LOG(LOG_LEVEL_DEBUG, " segment index %d segment_size %d", - segment_count, segment_size); + LOG_DEVEL(LOG_LEVEL_DEBUG, " segment index %d segment_size %d", + segment_count, segment_size); index += segment_size; segment_count++; } s_mark_end(s); s_pop_layer(s, iso_hdr); out_uint16_le(s, segment_count); - LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_wire_to_surface2: segment_count %d", - segment_count); + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_egfx_wire_to_surface2: segment_count %d", + segment_count); return s; } @@ -651,8 +651,8 @@ xrdp_egfx_send_wire_to_surface2(struct xrdp_egfx *egfx, int surface_id, codec_context_id, pixel_format, bitmap_data, bitmap_data_length); error = xrdp_egfx_send_s(egfx, s); - LOG(LOG_LEVEL_DEBUG, "xrdp_egfx_send_wire_to_surface2: xrdp_egfx_send_s " - "error %d", error); + LOG_DEVEL(LOG_LEVEL_DEBUG, "xrdp_egfx_send_wire_to_surface2: xrdp_egfx_send_s " + "error %d", error); free_stream(s); return error; }