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/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..11d50bdd 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 @@ -75,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/common/os_calls.c b/common/os_calls.c index d8062f72..b8f6b633 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; } @@ -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 a9cf8f5d..aa64b41f 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); @@ -397,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/common/xrdp_client_info.h b/common/xrdp_client_info.h index f2d91ad7..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]; @@ -215,8 +217,24 @@ 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, + GFX_H264 = 1 << 2, + 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/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/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 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/libxrdp/xrdp_sec.c b/libxrdp/xrdp_sec.c index 20665dfc..f2d1a4d4 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,30 @@ 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; } - +#ifdef XRDP_RFXCODEC + if (earlyCapabilityFlags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) + { + 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; @@ -2365,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 64d7ef7c..673275ef 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; 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/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 0db9f35b..6c1c4e0c 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 @@ -500,7 +505,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 @@ -543,7 +549,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, @@ -645,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_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; } diff --git a/xrdp/xrdp_encoder.c b/xrdp/xrdp_encoder.c index 03203cd7..fb89b346 100644 --- a/xrdp/xrdp_encoder.c +++ b/xrdp/xrdp_encoder.c @@ -27,14 +27,31 @@ #include "ms-rdpbcgr.h" #include "thread_calls.h" #include "fifo.h" +#include "xrdp_egfx.h" #ifdef XRDP_RFXCODEC #include "rfxcodec_encode.h" #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 */ +static const unsigned char g_rfx_quantization_values[] = +{ + 0x66, 0x66, 0x77, 0x87, 0x98, + 0x76, 0x77, 0x88, 0x98, 0x99 +}; +#endif + +struct enc_rect +{ + short x1; + short y1; + short x2; + short y2; +}; /*****************************************************************************/ static int @@ -42,6 +59,8 @@ 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); @@ -52,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); } @@ -70,6 +89,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]; @@ -77,52 +98,70 @@ 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) { - 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]; 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 = 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; + } 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; 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) { - 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; - 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 +170,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 +187,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); @@ -161,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) { @@ -174,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 @@ -223,28 +293,31 @@ 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"); 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"); @@ -253,26 +326,29 @@ 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 + 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; 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; @@ -313,28 +389,31 @@ 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", - 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; all_tiles_written = 0; + encode_passes = 0; 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) { @@ -346,26 +425,26 @@ 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; 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; + 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; @@ -373,13 +452,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, tiles_left, 0, 0); + + 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_rfx, + out_data + XRDP_SURCMD_PREFIX_BYTES, + &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); } + ++encode_passes; } LOG_DEVEL(LOG_LEVEL_DEBUG, @@ -397,16 +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; - + 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 */ @@ -414,12 +505,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 @@ -429,10 +520,497 @@ 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; } +#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 59bebaa8..8dc1311b 100644 --- a/xrdp/xrdp_encoder.h +++ b/xrdp/xrdp_encoder.h @@ -3,7 +3,14 @@ #define _XRDP_ENCODER_H #include "arch.h" -struct fifo; +#include "fifo.h" +#include "xrdp_client_info.h" + +#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; @@ -22,21 +29,34 @@ 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; 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 */ -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; @@ -44,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 { @@ -63,6 +92,26 @@ struct xrdp_enc_data_done int y; int cx; int cy; + 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 ccade62a..4a7e9073 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", @@ -79,7 +67,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; } @@ -164,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); } @@ -424,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); @@ -956,7 +952,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; @@ -973,8 +970,13 @@ 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_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); bwidth = rect->right - rect->left; bheight = rect->bottom - rect->top; if ((bwidth < 1) || (bheight < 1)) @@ -1019,6 +1021,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 " @@ -1057,11 +1061,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, @@ -1069,6 +1073,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 +1083,37 @@ 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; +} + +/******************************************************************************/ +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; } /******************************************************************************/ @@ -1133,6 +1165,342 @@ 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; +} + +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_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, + 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; + struct ver_flags_t *ver_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"); + } + /* 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 = 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: /* FALLTHROUGH */ + case XR_RDPGFX_CAPVERSION_101: + 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: + if (!(flags & XR_RDPGFX_CAPS_FLAG_AVC_DISABLED)) + { + best_h264_index = index; + } + best_pro_index = index; + break; + 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; + default: + /* just skip unknwown */ + LOG(LOG_LEVEL_INFO, "unknown version 0x%8.8x", version); + 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", + ver_flags[best_index].version, ver_flags[best_index].flags); + error = xrdp_egfx_send_capsconfirm(self->egfx, + 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, + 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_mm_egfx_create_surfaces(self); + 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); + } + g_free(ver_flags); + 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->gfx)) + { + 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; @@ -1156,27 +1524,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) @@ -1195,10 +1542,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; } @@ -1263,7 +1611,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; } @@ -1283,6 +1632,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:"); @@ -1314,12 +1666,67 @@ 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->resize_data->using_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 *) (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: @@ -1332,9 +1739,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) { @@ -1343,9 +1751,15 @@ 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_XRDP_CORE_RESIZE); + advance_resize_state_machine( + mm, WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING); break; - case WMRZ_XRDP_CORE_RESIZE: + // 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_RESET); + break; + case WMRZ_XRDP_CORE_RESET: // TODO: Unify this logic with server_reset error = libxrdp_reset( wm->session, desc_width, desc_height, wm->screen->bpp); @@ -1365,6 +1779,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) @@ -1394,6 +1814,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 (mm->resize_data->using_egfx) + { + 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: @@ -1404,6 +1840,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) @@ -1413,11 +1859,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: @@ -1444,7 +1885,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) { @@ -1497,6 +1938,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 @@ -1512,6 +1954,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" @@ -1546,6 +1993,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:"); @@ -1561,9 +2010,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; } @@ -1577,6 +2037,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 @@ -1587,10 +2053,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; } @@ -1613,6 +2086,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 @@ -2789,7 +3277,8 @@ xrdp_mm_connect_sm(struct xrdp_mm *self) } } - +#define MIN_MS_BETWEEN_FRAMES 40 +#define MIN_MS_TO_WAIT_FOR_MORE_UPDATES 0 /*****************************************************************************/ int xrdp_mm_get_wait_objs(struct xrdp_mm *self, @@ -2836,6 +3325,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; } @@ -2913,28 +3421,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) @@ -2945,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) { @@ -2958,31 +3447,52 @@ 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) { - if (!enc_done->continuation) + if (is_gfx) { - libxrdp_fastpath_send_frame_marker(self->wm->session, 0, - enc_done->enc->frame_id); + xrdp_egfx_send_data(self->egfx, + enc_done->comp_pad_data + + enc_done->pad_bytes, + enc_done->comp_bytes); } - 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 { - libxrdp_fastpath_send_frame_marker(self->wm->session, 1, - enc_done->enc->frame_id); + 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->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->frame_id); + } } } /* free enc_done */ @@ -2990,19 +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 (self->wm->client_info->use_frame_acks == 0) + if (got_frame_id) { - self->mod->mod_frame_ack(self->mod, - enc->flags, - enc->frame_id); + if (client_ack) + { + self->encoder->frame_id_server = enc_done->frame_id; + xrdp_mm_update_module_frame_ack(self); + } + else + { + self->mod->mod_frame_ack(self->mod, 0, + enc_done->frame_id); + } + } + if (is_gfx) + { + g_free(enc->u.gfx.cmd); } else { - self->encoder->frame_id_server = 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); @@ -3015,6 +3534,80 @@ 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; + int rv = 0; + + 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) + { + rv = 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; + rv = xrdp_mm_egfx_send_planar_bitmap(self, + self->wm->screen, + &rect, + surface_id, + mi->left, mi->top); + } + } + xrdp_region_delete(mon_reg); + } + } + return rv; +} + /*****************************************************************************/ int xrdp_mm_check_wait_objs(struct xrdp_mm *self) @@ -3095,8 +3688,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); @@ -3104,11 +3695,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); - } + 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; @@ -3137,8 +3724,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 @@ -3383,9 +3971,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) { @@ -3400,7 +3990,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) { @@ -3415,9 +4005,9 @@ server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, 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) { @@ -3427,32 +4017,32 @@ server_paint_rects_ex(struct xrdp_mod *mod, int num_drects, short *drects, 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) @@ -3471,7 +4061,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) @@ -3507,6 +4102,61 @@ 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; + if (mm->encoder == NULL) + { + if (data != NULL) + { + g_munmap(data, data_bytes); + } + return 1; + } + 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, @@ -3790,8 +4440,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) { @@ -3804,6 +4462,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_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_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; diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 5f8a7300..0d83a09b 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 @@ -181,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 */ @@ -343,8 +347,12 @@ enum display_resize_state WMRZ_EGFX_CONN_CLOSED, WRMZ_EGFX_DELETE, WMRZ_SERVER_MONITOR_RESIZE, - WMRZ_SERVER_VERSION_MESSAGE, - WMRZ_XRDP_CORE_RESIZE, + WMRZ_SERVER_VERSION_MESSAGE_START, + WMRZ_SERVER_MONITOR_MESSAGE_PROCESSING, + WMRZ_SERVER_MONITOR_MESSAGE_PROCESSED, + WMRZ_XRDP_CORE_RESET, + WMRZ_XRDP_CORE_RESET_PROCESSING, + WMRZ_XRDP_CORE_RESET_PROCESSED, WMRZ_EGFX_INITIALIZE, WMRZ_EGFX_INITALIZING, WMRZ_EGFX_INITIALIZED, @@ -362,8 +370,17 @@ 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_XRDP_CORE_RESIZE ? "WMRZ_XRDP_CORE_RESIZE" : \ + (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_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" : \ @@ -374,6 +391,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 +434,8 @@ struct xrdp_mm int dynamic_monitor_chanid; struct xrdp_egfx *egfx; int egfx_up; - + enum xrdp_egfx_flags 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..fcf59e55 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 { @@ -2020,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; diff --git a/xup/xup.c b/xup/xup.c index 4215d0bc..b9c17d74 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,15 +1227,64 @@ 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); 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 @@ -1289,7 +1327,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; @@ -1382,7 +1420,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; @@ -1628,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; @@ -1679,74 +1720,97 @@ 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); + 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); + s->p = phold + len; } - else if (type == 3) /* order list with len after type */ + } + 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) { - for (index = 0; index < num_orders; index++) + phold = s->p; + in_uint16_le(s, type); + in_uint16_le(s, len); + switch (type) { - phold = s->p; - in_uint16_le(s, type); - in_uint16_le(s, len); - rv = lib_mod_process_orders(mod, type, s); - - if (rv != 0) - { + 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; } + s->p = phold + len; } - else - { - LOG_DEVEL(LOG_LEVEL_TRACE, "unknown type %d", type); - } + } + else + { + LOG_DEVEL(LOG_LEVEL_TRACE, "unknown type %d", type); } return rv; 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 */