Skip to content

Commit

Permalink
Resize state machine: A fix and a question (#2929)
Browse files Browse the repository at this point in the history
* Store EGFX state before entering resize state machine

At present the EGFX state is destroyed by states WMRZ_EGFX_DELETE_SURFACE
through WRMZ_EGFX_DELETE. This means that at WMRZ_EGFX_INITIALIZE we
cannot distinguish between EGFX not being ever used, and EGFX
having been torn down. Consequently, when running non-GFX, we don't
correctly recover the session.

* Allow multiple reasons for suppress_output

Replaces the single boolean for suppress_output with
a bitmask, to allow output to be suppressed for
more than one reason

* Disable output during resize

* Add states to dynamic resize

Adds states to the dynamic resize state machine so we wait for a
Deactivation-Reactivation sequence to finish before sending pointer
updates, etc.

* suppress module output during the dynamic resize

* Add support for dynamic resize to VNC backend

xrdp_mm needs to be informed when a resize has been performed so that
the resize stte machine can be updsate.
  • Loading branch information
matt335672 authored Jan 31, 2024
1 parent 7277860 commit 9753559
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 65 deletions.
10 changes: 9 additions & 1 deletion common/xrdp_client_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -227,6 +229,12 @@ enum xrdp_encoder_flags
KEY_FRAME_REQUESTED = 1 << 3
};

/*
* Return true if output is suppressed for a particular reason
*/
#define OUTPUT_SUPPRESSED_FOR_REASON(ci,reason) \
(((ci)->suppress_output_mask & (unsigned int)reason) != 0)

/* yyyymmdd of last incompatible change to xrdp_client_info */
/* also used for changes to all the xrdp installed headers */
#define CLIENT_INFO_CURRENT_VERSION 20230425
Expand Down
6 changes: 6 additions & 0 deletions libxrdp/libxrdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 29 additions & 0 deletions libxrdp/libxrdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 *
Expand Down
128 changes: 78 additions & 50 deletions libxrdp/xrdp_rdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"))
{
return 1;
}
in_uint8(s, allowDisplayUpdates);
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_SUPPRESS_OUTPUT_PDU "
"allowDisplayUpdates %d", allowDisplayUpdates);
switch (allowDisplayUpdates)
if (s_check_rem_and_log(s, 1, "Parsing [MS-RDPBCGR] TS_SUPPRESS_OUTPUT_PDU"))
{
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;
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;
}
}
return 0;
return rv;
}

/*****************************************************************************/
Expand Down
6 changes: 6 additions & 0 deletions vnc/vnc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
5 changes: 5 additions & 0 deletions xrdp/xrdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -471,13 +471,18 @@ 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
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
Expand Down
Loading

0 comments on commit 9753559

Please sign in to comment.