Skip to content

Commit

Permalink
Unify monitor processing logic.
Browse files Browse the repository at this point in the history
There are two places where monitor descriptions are passed through the
RDP protocol:

- TS_UD_CS_MONITOR
- DISPLAYCONTROL_PDU_TYPE_MONITOR_LAYOUT

The processing logic for both of them is similar enough that they should
be unified.

Note that this is also the first step to making resizing work with the
Extension GFX channel.
  • Loading branch information
Nexarian committed May 25, 2021
1 parent 70a8af1 commit dfad088
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 181 deletions.
21 changes: 21 additions & 0 deletions common/xrdp_client_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,34 @@
#if !defined(XRDP_CLIENT_INFO_H)
#define XRDP_CLIENT_INFO_H

/*
* 2.2.1.3.6.1 Monitor Definition (TS_MONITOR_DEF)
* 2.2.1.3.9.1 Monitor Attributes (TS_MONITOR_ATTRIBUTES)
*/
struct monitor_info
{
int left;
int top;
int width;
int height;
int right;
int bottom;
int physical_width;
int physical_height;
int orientation;
int desktop_scale_factor;
int device_scale_factor;
int is_primary;
int flags;
};

struct display_size_description
{
int monitorCount; /* number of monitors detected (max = 16) */
struct monitor_info minfo[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS]; /* client monitor data */
struct monitor_info minfo_wm[CLIENT_MONITOR_DATA_MAXIMUM_MONITORS]; /* client monitor data, non-negative values */
int session_width;
int session_height;
};

/**
Expand Down
249 changes: 140 additions & 109 deletions libxrdp/xrdp_sec.c
Original file line number Diff line number Diff line change
Expand Up @@ -2298,159 +2298,190 @@ xrdp_sec_process_mcs_data_channels(struct xrdp_sec *self, struct stream *s)
return 0;
}

/*****************************************************************************/
/* Process a [MS-RDPBCGR] TS_UD_CS_MONITOR message.
reads the client monitors data */
static int
xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s)
{
int index;
int monitorCount;
int flags;
int x1;
int y1;
int x2;
int y2;
int got_primary;
struct xrdp_client_info *client_info = (struct xrdp_client_info *)NULL;
struct display_size_description*
process_monitor_stream(struct stream *s, int full_parameters) {
struct display_size_description *description = (struct display_size_description *)
g_malloc(sizeof(struct display_size_description), 1);

client_info = &(self->rdp_layer->client_info);
int NumMonitor;
struct monitor_info *monitor_layout;
struct xrdp_rect rect = {8192, 8192, -8192, -8192};
int got_primary = 0;

/* this is an option set in xrdp.ini */
if (client_info->multimon != 1) /* are multi-monitors allowed ? */
{
LOG(LOG_LEVEL_INFO, "Multi-monitor is disabled by server config");
return 0;
}
if (!s_check_rem_and_log(s, 8, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR"))
{
return 1;
}
in_uint32_le(s, flags); /* flags */
in_uint32_le(s, monitorCount);
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] TS_UD_CS_MONITOR "
"flags 0x%8.8x, monitorCount %d", flags, monitorCount);
in_uint32_le(s, NumMonitor);
LOG(LOG_LEVEL_DEBUG, " NumMonitor %d", NumMonitor);

//verify flags - must be 0x0
if (flags != 0)
{
LOG(LOG_LEVEL_ERROR,
"[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR flags MUST be zero, "
"received: 0x%8.8x", flags);
return 1;
}
//verify monitorCount - max 16
if (monitorCount > 16)
if (NumMonitor >= CLIENT_MONITOR_DATA_MAXIMUM_MONITORS)
{
LOG(LOG_LEVEL_ERROR,
"[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR monitorCount "
"MUST be less than 16, received: %d", monitorCount);
return 1;
"MUST be less than 16, received: %d", NumMonitor);
goto exit_error;
}

client_info->monitorCount = monitorCount;
description->monitorCount = NumMonitor;

x1 = 0;
y1 = 0;
x2 = 0;
y2 = 0;
got_primary = 0;
/* Add client_monitor_data to client_info struct, will later pass to X11rdp */
for (index = 0; index < monitorCount; index++)
for (int monitor_index = 0; monitor_index < NumMonitor; ++monitor_index)
{
if (!s_check_rem_and_log(s, 20, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR.TS_MONITOR_DEF"))
if (!s_check_rem_and_log(s, full_parameters == 0 ? 20 : 40, "Parsing monitor definitions."))
{
return 1;
goto exit_error;
}
in_uint32_le(s, client_info->minfo[index].left);
in_uint32_le(s, client_info->minfo[index].top);
in_uint32_le(s, client_info->minfo[index].right);
in_uint32_le(s, client_info->minfo[index].bottom);
in_uint32_le(s, client_info->minfo[index].is_primary);

LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] "
"TS_UD_CS_MONITOR.TS_MONITOR_DEF %d "
"left %d, top %d, right %d, bottom %d, flags 0x%8.8x",
index,
client_info->minfo[index].left,
client_info->minfo[index].top,
client_info->minfo[index].right,
client_info->minfo[index].bottom,
client_info->minfo[index].is_primary);

if (index == 0)
{
x1 = client_info->minfo[index].left;
y1 = client_info->minfo[index].top;
x2 = client_info->minfo[index].right;
y2 = client_info->minfo[index].bottom;

monitor_layout = description->minfo + monitor_index;
if (full_parameters != 0) {
in_uint32_le(s, monitor_layout->flags);
}
in_uint32_le(s, monitor_layout->left);
in_uint32_le(s, monitor_layout->top);
in_uint32_le(s, monitor_layout->width);
in_uint32_le(s, monitor_layout->height);
if (full_parameters != 0) {
in_uint32_le(s, monitor_layout->physical_width);
in_uint32_le(s, monitor_layout->physical_height);
in_uint32_le(s, monitor_layout->orientation);
in_uint32_le(s, monitor_layout->desktop_scale_factor);
in_uint32_le(s, monitor_layout->device_scale_factor);
}

monitor_layout->right = monitor_layout->left + monitor_layout->width;
monitor_layout->bottom = monitor_layout->top + monitor_layout->height;

if (full_parameters != 0)
{
LOG(LOG_LEVEL_INFO, " Index: %d, Flags 0x%8.8x Left %d Top %d "
"Width %d Height %d PhysicalWidth %d PhysicalHeight %d "
"Orientation %d DesktopScaleFactor %d DeviceScaleFactor %d",
monitor_index, monitor_layout->flags, monitor_layout->left,
monitor_layout->top, monitor_layout->width, monitor_layout->height,
monitor_layout->physical_width, monitor_layout->physical_height,
monitor_layout->orientation, monitor_layout->desktop_scale_factor,
monitor_layout->device_scale_factor);
}
else
{
x1 = MIN(x1, client_info->minfo[index].left);
y1 = MIN(y1, client_info->minfo[index].top);
x2 = MAX(x2, client_info->minfo[index].right);
y2 = MAX(y2, client_info->minfo[index].bottom);
LOG_DEVEL(LOG_LEVEL_TRACE, "Received [MS-RDPBCGR] "
"TS_UD_CS_MONITOR.TS_MONITOR_DEF %d "
"left %d, top %d, right %d, bottom %d, flags 0x%8.8x",
monitor_index,
monitor_layout->left,
monitor_layout->top,
monitor_layout->right,
monitor_layout->bottom,
monitor_layout->is_primary);
}

if (client_info->minfo[index].is_primary)
if (monitor_index == 0)
{
got_primary = 1;
rect.left = monitor_layout->left;
rect.top = monitor_layout->top;
rect.right = monitor_layout->right;
rect.bottom = monitor_layout->bottom;
}
else
{
rect.left = MIN(monitor_layout->left, rect.left);
rect.top = MIN(monitor_layout->top, rect.top);
rect.right = MAX(rect.right, monitor_layout->right);
rect.bottom = MAX(rect.bottom, monitor_layout->bottom);
}

LOG(LOG_LEVEL_DEBUG,
"Client monitor [%d]: left= %d, top= %d, right= %d, bottom= %d, "
"is_primary?= %d",
index,
client_info->minfo[index].left,
client_info->minfo[index].top,
client_info->minfo[index].right,
client_info->minfo[index].bottom,
client_info->minfo[index].is_primary);
if (monitor_layout->is_primary)
{
got_primary = 1;
}
}

if (!got_primary)
{
/* no primary monitor was set, choose the leftmost monitor as primary */
for (index = 0; index < monitorCount; index++)
for (int monitor_index = 0; monitor_index < NumMonitor; ++monitor_index)
{
if (client_info->minfo[index].left == x1 &&
client_info->minfo[index].top == y1)
monitor_layout = description->minfo + monitor_index;
if (monitor_layout->left != rect.left || monitor_layout->top != rect.top)
{
client_info->minfo[index].is_primary = 1;
break;
continue;
}
monitor_layout->is_primary = 1;
}
}

/* set wm geometry */
if ((x2 > x1) && (y2 > y1))
if ((rect.right > rect.left) && (rect.bottom > rect.top))
{
client_info->width = (x2 - x1) + 1;
client_info->height = (y2 - y1) + 1;
description->session_width = rect.right - rect.left;
description->session_height = rect.bottom - rect.top;
}
/* make sure virtual desktop size is ok */
if (client_info->width > 0x7FFE || client_info->width < 0xC8 ||
client_info->height > 0x7FFE || client_info->height < 0xC8)
if (description->session_width > 0x7FFE || description->session_width < 0xC8 ||
description->session_height > 0x7FFE || description->session_height < 0xC8)
{
LOG(LOG_LEVEL_ERROR,
LOG(LOG_LEVEL_INFO,
"Client supplied virtual desktop width or height is invalid. "
"Allowed width range: min %d, max %d. Width received: %d. "
"Allowed height range: min %d, max %d. Height received: %d",
0xC8, 0x7FFE, client_info->width,
0xC8, 0x7FFE, client_info->height);
return 1; /* error */
0xC8, 0x7FFE, description->session_width,
0xC8, 0x7FFE, description->session_width);
goto exit_error;
}

/* keep a copy of non negative monitor info values for xrdp_wm usage */
for (index = 0; index < monitorCount; index++)
for (int monitor_index = 0; monitor_index < NumMonitor; ++monitor_index)
{
client_info->minfo_wm[index].left = client_info->minfo[index].left - x1;
client_info->minfo_wm[index].top = client_info->minfo[index].top - y1;
client_info->minfo_wm[index].right = client_info->minfo[index].right - x1;
client_info->minfo_wm[index].bottom = client_info->minfo[index].bottom - y1;
client_info->minfo_wm[index].is_primary = client_info->minfo[index].is_primary;
monitor_layout = description->minfo_wm + monitor_index;

g_memcpy(monitor_layout, description->minfo + monitor_index, sizeof(struct monitor_info));

monitor_layout->left = monitor_layout->left - rect.left;
monitor_layout->top = monitor_layout->top - rect.top;
monitor_layout->right = monitor_layout->right - rect.left;
monitor_layout->bottom = monitor_layout->bottom - rect.top;
}
return description;
exit_error:
g_free(description);
return NULL;
}

/*****************************************************************************/
/* Process a [MS-RDPBCGR] TS_UD_CS_MONITOR message.
reads the client monitors data */
static int
xrdp_sec_process_mcs_data_monitors(struct xrdp_sec *self, struct stream *s)
{
int flags;
struct xrdp_client_info *client_info = &(self->rdp_layer->client_info);

/* this is an option set in xrdp.ini */
if (client_info->multimon != 1) /* are multi-monitors allowed ? */
{
LOG(LOG_LEVEL_INFO, "Multi-monitor is disabled by server config");
return 0;
}
if (!s_check_rem_and_log(s, 8, "Parsing [MS-RDPBCGR] TS_UD_CS_MONITOR"))
{
return 1;
}
in_uint32_le(s, flags); /* flags */

//verify flags - must be 0x0
if (flags != 0)
{
LOG(LOG_LEVEL_ERROR,
"[MS-RDPBCGR] Protocol error: TS_UD_CS_MONITOR flags MUST be zero, "
"received: 0x%8.8x", flags);
return 1;
}

struct display_size_description *description = process_monitor_stream(s, 0);

client_info->monitorCount = description->monitorCount;
client_info->width = description->session_width;
client_info->height = description->session_height;
g_memcpy(client_info->minfo, description->minfo, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS);
g_memcpy(client_info->minfo_wm, description->minfo_wm, sizeof(struct monitor_info) * CLIENT_MONITOR_DATA_MAXIMUM_MONITORS);

g_free(description);

return 0;
}
Expand Down
Loading

0 comments on commit dfad088

Please sign in to comment.